Compare commits

...
283 Commits
Author SHA1 Message Date
Kevin Darby cbf1fad2dd Merge branch 'master' of bitbucket.org:bluetradesys/spark into ml 2019-02-11 11:30:08 -05:00
Jake Norbut 8a3a35a822 Merged in SPARK-2025 (pull request #160)
RTM - SPARK-2025

Approved-by: John Colvin <john.colvin@bluetradesys.com>
2019-02-11 15:01:35 +00:00
Pedro Pinto 924b654f5f Update release notes. 2019-02-11 09:53:30 -05:00
Pedro Pinto dac01b3004 Merge branch 'master' into SPARK-2025 2019-02-11 09:49:19 -05:00
Pedro Pinto 508c542d56 Merge branch 'master' into SPARK-2025 2019-02-11 09:46:57 -05:00
Jake Norbut 9586b72653 Merged in SPARK-1975 (pull request #155)
RTM - SPARK-1975

Approved-by: Eric Harding <eric.harding@bluetradesys.com>
2019-02-11 14:45:32 +00:00
Pedro Pinto ee21b4f597 Updated release notes. 2019-02-11 09:42:37 -05:00
Pedro Pinto 964b516504 Merge branch 'master' into SPARK-1975 2019-02-11 09:23:46 -05:00
Pedro Pinto be6124e72f Updated release notes. 2019-02-11 09:06:05 -05:00
Eric Harding 578b9e7570 Merged in api_manual (pull request #159)
RTM: Add ApiThreading man page
2019-02-11 14:01:52 +00:00
Pedro Pinto fd66ef6993 Merge branch 'master' into api_manual 2019-02-11 08:59:24 -05:00
Pedro Pinto 1301130afb Quieted the build. 2019-02-11 08:58:00 -05:00
Jake Norbut 7daa96d246 Merged in SPARK-1513 (pull request #158)
RTM - SPARK-1513
2019-02-11 13:56:09 +00:00
Pedro Pinto 49e5eab7d3 Updated release notes. 2019-02-11 08:55:10 -05:00
Michael Harding fee4541e38 Merged in clip_limits_fix (pull request #162)
RTM Fix clip limits test
2019-02-11 13:38:30 +00:00
Kevin Darby 1fbc1584e5 Merge branch 'algos2' of bitbucket.org:bluetradesys/spark into ml 2019-02-08 17:19:16 -05:00
Kevin Darby 02defef93d oco testing 2019-02-08 14:55:16 -05:00
Michael Harding 9132b4a178 Fix clip limits test 2019-02-08 12:37:09 -05:00
Kevin Darby 9390fb0639 per Brian standardizing on Stop Ticks, Stop Type, Profit Ticks, Profit Type 2019-02-06 17:41:24 -05:00
Kevin Darby 82a8d007bf only generate package on release build 2019-02-06 17:06:22 -05:00
Kevin Darby cff32ad09a for now I'd like to keep these client and server docs separate since they are two repos 2019-02-06 17:03:23 -05:00
Eric Harding 7b9071a1b2 Review feedback 2 2019-02-06 14:49:17 -05:00
Eric Harding 99f1d1fa01 Review feedback 2019-02-06 14:48:18 -05:00
Jake Norbut 03fe75cfd2 commit button now unselects row 2019-02-06 13:38:40 -06:00
Eric Harding a7d71fe170 Move ApiThreading doc 2019-02-06 14:31:04 -05:00
Eric Harding 00ce3adde5 Add ApiThreading man page (draft) 2019-02-06 13:10:18 -05:00
Kevin Darby 6d774d46c9 Merge branch 'master' of bitbucket.org:bluetradesys/spark into algos2 2019-02-05 17:51:13 -05:00
Kevin Darby b39812aad0 add RelativeSide enum for OCO. Fix SPARK-2022 2019-02-05 17:50:08 -05:00
Jake Norbut fb059e5571 refine comment 2019-02-05 14:36:51 -06:00
Jake Norbut 1864c27584 Anything that used to hit get_cme_gen_open now hits get_start_of_trading_day 2019-02-05 14:35:10 -06:00
Kevin Darby 8b7f31ccd6 Merged in update_sdk_docs (pull request #151)
RTM: SPARK-1983, SPARK-1985, SPARK-1982, SPARK-1981

Approved-by: Eric Harding <eric.harding@bluetradesys.com>
2019-02-05 19:37:39 +00:00
Eric Harding b91f998239 Merged in replay_fallback (pull request #156)
RTM: Replay fallback
2019-02-05 19:37:18 +00:00
Pedro Pinto 183916118e Merged in limit_bug (pull request #157)
Fixed limit enforcement bug in order activation.

Approved-by: Kevin Darby <kevin.darby@bluetradesys.com>
2019-02-05 19:36:57 +00:00
Pedro Pinto 8d200ee7f3 Added to release notes. 2019-02-05 14:32:25 -05:00
Pedro Pinto d59d6fd095 Fixed limit enforcement bug in order activation. 2019-02-05 14:19:01 -05:00
Eric Harding c53f69bc53 Fix Launch.json working directory 2019-02-05 14:06:50 -05:00
Eric Harding e234a76199 Fall back to data_files if http://mdreplay or download cache are not available. 2019-02-05 12:34:11 -05:00
Eric Harding cf432a82a0 Add a small md recording to the build for offline access. Automatically unxz data_files 2019-02-05 12:33:43 -05:00
Jake Norbut 5b40b4b4ca Hiding Security Key column in default settings in all grids 2019-02-05 11:14:40 -06:00
Jake Norbut dd6b415ce7 remove trade key column from Time and Sales 2019-02-05 11:06:55 -06:00
Kevin Darby f99717d880 Merge branch 'master' of bitbucket.org:bluetradesys/spark into algos2 2019-02-05 10:03:16 -05:00
Jake Norbut b61cf170fe release notes refinement 2019-02-05 08:28:46 -06:00
Jake Norbut 7915c84b6a updating notes 2019-02-04 18:30:28 -06:00
Jake Norbut 3aece4fb97 Merged in SPARK-1987 (pull request #154)
RTM - SPARK-1986, SPARK-1987

Approved-by: Eric Harding <eric.harding@bluetradesys.com>
2019-02-04 22:40:39 +00:00
Kevin Darby f224b8be43 Merge branch 'master' of bitbucket.org:bluetradesys/spark into algos2 2019-02-04 16:57:05 -05:00
Jake Norbut be4dd05ba6 hiding Hidden and price type 2019-02-04 14:43:22 -06:00
Jake Norbut 570b362a7e release notes - words 2019-02-04 14:20:50 -06:00
Jake Norbut 944714adc5 Updating release notes describing Floating Order Book 2019-02-04 14:19:43 -06:00
Pedro Pinto fee7dcedb8 Merged in dev_doc (pull request #127)
Dev doc
2019-02-04 20:14:30 +00:00
Pedro Pinto 0883b91ef8 dev_process.md edited online with Bitbucket 2019-02-04 20:14:17 +00:00
Kevin Darby f43269f688 Merged in proto36 (pull request #153)
RTM move externals pointer to proto36, small changes in spark to support that

Approved-by: Pedro Pinto <pedro.pinto+atlassian@bluetradesys.com>
2019-02-04 20:10:00 +00:00
Jake Norbut 20728b7e8c Merged in miniob (pull request #149)
RTM - Mini OrderBook

Approved-by: Pedro Pinto <pedro.pinto+atlassian@bluetradesys.com>
2019-02-04 20:08:31 +00:00
Pedro Pinto b53060d665 Added release notes 2019-02-04 15:05:49 -05:00
Pedro Pinto 01d94748a2 Merge branch 'miniob' of bitbucket.org:bluetradesys/spark into miniob 2019-02-04 15:02:59 -05:00
Pedro Pinto ee4ebd8ccf Trying to fix the linux/win war on CMAkeDeps.cmake 2019-02-04 15:02:16 -05:00
Eric Harding ef3e3d6edc Wait to give obvm obvm a chance to load rows and not flash 2019-02-04 14:55:33 -05:00
Jake Norbut 6d4ff5707c PR edits - Style cop 2019-02-04 13:20:39 -06:00
Jake Norbut 158b8ac64d PR edit - simplify LINQ expressions when using Where and FirstOrDefault 2019-02-04 13:17:24 -06:00
Jake Norbut c11fc37781 PR - naming 2019-02-04 13:12:33 -06:00
Jake Norbut e3ca2194d0 PR edit - changing orderbook_vm property to method to better reflect the nature of the beast 2019-02-04 13:11:24 -06:00
Jake Norbut e49c8e32f2 PR edits - Simplifying XAML since UserControl is a ContentControl 2019-02-04 13:01:51 -06:00
Jake Norbut 63754199bf PR edits - Hashset for the win over List for Contains 2019-02-04 12:40:19 -06:00
Jake Norbut 7af568a620 PR edit; Set is your friend 2019-02-04 12:34:56 -06:00
Jake Norbut dcf509d21b PR edits - devolving qty/dirty and price/dirty 2019-02-04 12:29:34 -06:00
Jake Norbut b8c3b36a98 PR edits 2019-02-04 11:34:04 -06:00
Jake Norbut 8e5afbfa40 PR edit; columns setter is now private 2019-02-04 11:27:58 -06:00
Jake Norbut 906031d1c3 MinWidth so that the vertical scrollbar does not cover up the content in the last column 2019-02-01 16:55:49 -06:00
Kevin Darby 5eedc1a977 moved that using std::vector out of header 2019-02-01 17:22:12 -05:00
Kevin Darby 021c163b64 move externals pointer to proto36, small changes in spark to support that 2019-02-01 16:41:11 -05:00
Jake Norbut c6c71f0b04 enforce max height on popop size 2019-02-01 15:38:55 -06:00
Jake Norbut bc8c01a789 move edit price immediately after edit qty 2019-02-01 15:24:29 -06:00
Jake Norbut b93f794116 remove ladder tooltip and backing property 2019-02-01 15:18:39 -06:00
Jake Norbut 5369e67c7a minor refactoring, some notes after talking w/ john 2019-02-01 12:04:34 -06:00
Jake Norbut 65c4b41c74 inline price ticker 2019-02-01 11:02:56 -06:00
Jake Norbut 2ce9f7db34 qty ticker layout changes 2019-01-31 14:29:04 -06:00
Jake Norbut ecad4471b3 auto close popup when no orders remain 2019-01-31 11:50:27 -06:00
Jake Norbut 9b4a99dcb7 darken popup border 2019-01-31 11:48:48 -06:00
Jake Norbut 8d805409d5 Merge branch 'master' of bitbucket.org:bluetradesys/spark into miniob 2019-01-31 08:08:23 -06:00
Jake Norbut 6a100bf3a6 remove checkin cruft 2019-01-30 19:30:13 -06:00
Jake Norbut 4047e5bdee making row stay in edit mode when a change has not yet been committed but the selection has been moved off the row 2019-01-30 19:24:50 -06:00
Kevin Darby 5aef712065 SPARK-1983, SPARK-1985, SPARK-1982, SPARK-1981 2019-01-30 18:18:21 -05:00
Jake Norbut dd19ac4bce hopefully use the right Dispatcher this time 2019-01-30 14:27:00 -06:00
Eric Harding ff2102e0cd Merged in run_system_tests (pull request #150)
RTM: Run system tests

Approved-by: Michael Harding <michael.harding@bluetradesys.com>
2019-01-30 18:17:03 +00:00
Eric Harding 29762512ad Merged master into run_system_tests 2019-01-30 12:06:39 -05:00
Eric Harding 289d40f24a Need spark_test.dll for system tests 2019-01-30 11:18:31 -05:00
Jake Norbut 947a905423 mini ob - inline qty tick up/down; formatting 2019-01-30 08:05:17 -06:00
Eric Harding dfe9ea12c3 provide_command_line for system_tests -configserver 2019-01-29 16:55:12 -05:00
Eric Harding a9c2261671 Simplify getting a security 2019-01-29 16:06:31 -05:00
Taha Afzal b8766089f0 Merge branch 'master' of bitbucket.org:bluetradesys/spark 2019-01-29 15:51:22 -05:00
Taha Afzal 18d3c268de Added trace corID to first quote udpate call (after getting the first ack) 2019-01-29 15:51:16 -05:00
Pedro Pinto fdf255a7a3 Improved md performance logs. 2019-01-29 14:58:13 -05:00
Pedro Pinto 995be6cfd0 Added forgotten security count metric back. 2019-01-29 14:53:53 -05:00
Eric Harding 52ac650c58 Merge branch 'master' of bitbucket.org:bluetradesys/spark into run_system_tests 2019-01-29 12:06:36 -05:00
Michael Harding 96c7cc1528 sparkcmd test --list now lists only the current TestType 2019-01-29 10:29:24 -05:00
Michael Harding d81ef8668c Return int from sparkcmd 2019-01-29 09:31:14 -05:00
Eric Harding dab95d7e91 Make sure every sparkcmd command respects -configserver 2019-01-29 09:23:54 -05:00
Eric Harding 88045ea432 Add netcore publish to jenkinsbuild.cmd 2019-01-29 09:23:35 -05:00
Pedro Pinto 01113e645a release_notes.md edited online with Bitbucket 2019-01-28 23:16:02 +00:00
Pedro Pinto 17c57878e1 removed duplicate entries in requote perf log. 2019-01-28 23:14:15 +00:00
Pedro Pinto 4357fbc410 Removed test code. 2019-01-28 17:21:52 +00:00
Pedro Pinto 7d216978a3 Updated release notes. 2019-01-28 12:02:32 -05:00
Taha Afzal fc3d84c02a Merged in SPARK-1939-HedgingSpeed (pull request #148)
RTM. Various hedging speede improvements
2019-01-28 16:59:46 +00:00
Taha Afzal f6fd9155b1 externa; 2019-01-28 11:58:32 -05:00
Taha Afzal 7723f1e004 merging from master 2019-01-28 11:09:17 -05:00
Taha Afzal 041a7988c1 Spreader.proto::enable_child_order_activate now controls the child order's activate call 2019-01-28 11:01:05 -05:00
Michael Harding daa9800af2 Merged in SPARK-1877-system-tests (pull request #147)
RTM SPARK-1877 system tests

Approved-by: Eric Harding <eric.harding@bluetradesys.com>
2019-01-28 14:54:36 +00:00
Michael Harding dcb10a3484 SPARK-1877: Add test for no rule. Implememnt PR suggestions. 2019-01-28 09:26:55 -05:00
Taha Afzal 70e826b212 Merge branch 'warmup_activate' into SPARK-1939-HedgingSpeed 2019-01-28 08:48:25 -05:00
Jake Norbut af737564aa Merged in SPARK-1977 (pull request #145)
RTM - high dpi grid column oddity

Approved-by: Eric Harding <eric.harding@bluetradesys.com>
2019-01-28 13:46:53 +00:00
Pedro Pinto 582f97d1ce Merged in ticker_events_in_api (pull request #144)
RTM. Ticker events in api

Approved-by: Taha Afzal <taha.afzal@bluetradesys.com>
Approved-by: Eric Harding <eric.harding@bluetradesys.com>
2019-01-28 13:46:15 +00:00
Taha Afzal a83c1eb633 calling ChildOrder's warm_up_activate() from Spreader 2019-01-28 07:26:18 -05:00
Pedro Pinto 1f893c73ad Added warm_up_activate method to ChildOrder to warm up cache. 2019-01-25 16:32:42 -05:00
Michael Harding ef755ea6fb SPARK-1877: Test Runner for multiple test types 2019-01-25 15:57:21 -05:00
Taha Afzal ebfc1bc485 Merge branch 'master' into SPARK-1939-HedgingSpeed 2019-01-25 13:34:55 -05:00
Jake Norbut a8646ebb3f adding comment back in 2019-01-24 13:45:59 -06:00
Jake Norbut 28fd04293b adding single-click delete/cancel functionality 2019-01-24 13:41:33 -06:00
Michael Harding 111767522f SPARK-1877: Clip Limits Test 2019-01-24 13:45:03 -05:00
Taha Afzal 429e16996a Merge branch 'SPARK-1939-HedgingSpeed' of bitbucket.org:bluetradesys/spark into SPARK-1939-HedgingSpeed 2019-01-24 13:35:29 -05:00
Taha Afzal 1ed85af40e spreader reports from the timer callback now 2019-01-24 13:35:23 -05:00
Kevin Darby f5457e5ce4 Merge branch 'master' of bitbucket.org:bluetradesys/spark into ml 2019-01-23 13:45:26 -05:00
Kevin Darby 7465a38022 Merged in sdk_build (pull request #146)
SPARK-1980 we need 7z on the jenkins server, not unzip

Approved-by: Pedro Pinto <pedro.pinto+atlassian@bluetradesys.com>
Approved-by: Kevin Darby <kevin.darby@bluetradesys.com>
2019-01-23 18:09:24 +00:00
Kevin Darby 8afa03cc62 SPARK-1980 we need 7z on the jenkins server, not unzip 2019-01-23 12:56:59 -05:00
Jake Norbut 26dfd89d6c Properly Dispose of the OrderBookVM when the popup closes 2019-01-23 10:07:07 -06:00
Pedro Pinto fe54d5b973 Fixed double counting bug in Iceberg when using pauses. 2019-01-23 10:57:43 -05:00
Jake Norbut e7b9c3e228 adding a border around the popup window 2019-01-23 09:43:19 -06:00
Jake Norbut ae5db799d4 MiniOB will have parent-child rows expanded by default 2019-01-23 09:43:03 -06:00
Kevin Darby 5ba746fd59 small merge issue 2019-01-22 16:31:11 -05:00
Kevin Darby ab5cb23062 Merge branch 'algos2' of bitbucket.org:bluetradesys/spark into ml 2019-01-22 16:11:28 -05:00
Kevin Darby 4ebdc603c5 Merge branch 'master' of bitbucket.org:bluetradesys/spark into algos2 2019-01-22 16:10:38 -05:00
Pedro Pinto d573688064 Update release notes. 2019-01-22 15:26:00 -05:00
Pedro Pinto 14c601034a Merged with master 2019-01-22 15:14:22 -05:00
Jake Norbut 3de65fb027 Create a new OrderbookVM each time; fixes crash when launching mini-ob from same badge multiple times 2019-01-22 12:37:53 -06:00
Jake Norbut 9de0c4f530 Remove ContextMenu from Badge and setup new Popup 2019-01-22 12:35:18 -06:00
Jake Norbut ce5998c5dd Adding a Popup dep prop to the Badge. Note - I don't think Ineed AffectsRender here 2019-01-22 12:27:57 -06:00
Jake Norbut dcbc6e756e DIYGrid - adding dep prop to allow rows horizontal scrollbar to be strictly collapsed 2019-01-22 12:23:00 -06:00
Pedro Pinto 4955c1a792 Improved performance of ll to time_point conversion. 2019-01-22 13:00:03 -05:00
Pedro Pinto 2990710b88 Avoided delivering entire trade buffer on first sub. 2019-01-22 12:59:16 -05:00
Pedro Pinto 280ae81860 size() is probably slower than empty() 2019-01-22 12:57:47 -05:00
Taha Afzal 5e713d9008 reverting hard coded changig in accidental push 2019-01-21 09:47:35 -05:00
Taha Afzal 763c2fa41a Merge branch 'master' into SPARK-1939-HedgingSpeed 2019-01-20 12:34:28 -05:00
Taha Afzal 9d170e32f1 log level for cache warming set to NoLog 2019-01-18 23:02:00 -05:00
Taha Afzal b4410f7412 Passing trace to Hedger 2019-01-18 18:37:32 -05:00
Michael Harding b702ce9479 System test in broken state for debugging 2019-01-18 16:41:21 -05:00
Michael Harding abc7b1e2e9 Merge branch 'master' into SPARK-1877-system-tests 2019-01-18 12:39:47 -05:00
Eric Harding f71ff0e306 Add the ability to control affinity for the md tail tool 2019-01-18 11:52:42 -05:00
Jake Norbut 3c82327f1a in case my machine starts on fire 2019-01-17 15:59:55 -06:00
Jake Norbut f3ac92c434 PR edits; Eric has ESP 2019-01-17 15:52:56 -06:00
Jake Norbut a8694d6fb2 Because this is the bugfix the spark client deserves, but not the ones it needs right now 2019-01-17 15:21:25 -06:00
Pedro Pinto 52e6536018 Merge branch 'SPARK-1939-HedgingSpeed' of bitbucket.org:bluetradesys/spark into SPARK-1939-HedgingSpeed 2019-01-17 13:46:24 -05:00
Pedro Pinto 42274edbc4 Added extra logging level for no logging code paths. 2019-01-17 13:45:26 -05:00
Taha Afzal 6d438b4764 New spreader test for muliple quoting legs 2019-01-17 13:19:56 -05:00
Pedro Pinto 3688ec0739 Moved externals pointer 2019-01-17 11:46:19 -05:00
Pedro Pinto ce8d27bb71 Added time to ticker update. 2019-01-17 11:44:37 -05:00
Pedro Pinto ee66ddf9a6 Fixed a few bugs in the ticker api code. 2019-01-17 10:48:11 -05:00
Pedro Pinto bea0e5ced7 Added ticker events to order manager api 2019-01-16 17:57:02 -05:00
Pedro Pinto b2d1d11826 Added ticker events to MD Source 2019-01-16 17:56:40 -05:00
Taha Afzal d075f2ad0c removed some extra logging data from CacheWarmingState 2019-01-16 13:37:04 -05:00
Taha Afzal 409bbdc0f9 when 'in_cache_warming_cycle' quoter order updates are surpressed (they should have been surpressed logically as well, but this is just an extra check since the outcome can be nasty) 2019-01-16 11:37:58 -05:00
Taha Afzal d4fd3900be added config key to enable cache warming 2019-01-15 14:39:38 -05:00
Taha Afzal e45736a692 putting the fake fill log messages o lower logging level 2019-01-15 09:25:06 -05:00
Taha Afzal bd8336e22b inlined add_new_hedger 2019-01-14 16:58:07 -05:00
Eric Harding f3dedfc4e3 Merged in SPARK-1966-add-cme-ticker-trade-details (pull request #143)
RTM: SPARK-1966 add cme ticker trade details
2019-01-14 21:35:51 +00:00
Jake Norbut 326bcb4544 Merged in SPARK-1960 (pull request #140)
RTM: locking _resources ResourceDictionary prior to indexer access

Approved-by: Eric Harding <eric.harding@bluetradesys.com>
2019-01-14 21:35:17 +00:00
Pedro Pinto 884cdef97b Merged in improve_perf_log_latency (pull request #139)
RTM. Improve perf log performance.
2019-01-14 21:34:48 +00:00
Eric Harding 5e3467e3b6 Add release note 2019-01-14 14:41:47 -05:00
Eric Harding 979c6e078a Remove misleading comments 2019-01-14 14:39:05 -05:00
Eric Harding 69f38daad7 SPARK-1966 Add CME ticker trade details 2019-01-14 14:37:51 -05:00
Taha Afzal a64d428a89 added comments and inlined some smaller functions 2019-01-14 14:34:49 -05:00
Taha Afzal 78c89c6677 Merge branch 'master' into SPARK-1939-HedgingSpeed 2019-01-14 11:07:16 -05:00
Taha Afzal 8d0d678c01 unused parameters rmeoved form add_new_hedger 2019-01-14 09:58:13 -05:00
Taha Afzal 8b9df305b4 took the ChildOrder initilization out of the critical hedging path 2019-01-13 21:57:13 -05:00
Taha Afzal 02ee5cc6d3 moved orderbuilders (not used) in the hot path away from the hot memory 2019-01-11 18:45:24 -05:00
Taha Afzal 207c93c972 All the leg data is in one place now inside the SpreaderLegData (as opposed to ref's to SpreaderBookkeepingData) 2019-01-11 17:49:23 -05:00
Eric Harding 14012a16da Add "all" option to sparkd md tail for emumba testing 2019-01-11 17:29:51 -05:00
Kevin Darby f4b7fbe6b5 didn't save 2019-01-11 16:05:57 -05:00
Kevin Darby 9901ef54d4 working on execution 2019-01-11 16:05:37 -05:00
Kevin Darby 293c13e11d we can load tf models in spark orders. Now we need to be able to execute them 2019-01-11 14:42:56 -05:00
Taha Afzal dc264e1063 fixing buid 2019-01-11 08:37:49 -05:00
Kevin Darby be4c69fad4 libtf 2019-01-10 23:45:37 -05:00
Taha Afzal 2e883808b6 LegPropertyData does not hold leg orderDefinitions any more 2019-01-10 21:34:45 -05:00
Kevin Darby 2c4dc8fbe5 externals 2019-01-10 18:23:22 -05:00
Kevin Darby 4ea93bc386 just needs some rpath and I'm in business 2019-01-10 18:22:03 -05:00
Michael Harding 184a900eea SPARK-1877: Add Limits Test; Limits Test sets and restores limits 2019-01-10 14:51:06 -05:00
Pedro Pinto 3bf086c73a Merged in SPARK-1970-manual-order-indicator (pull request #142)
RTM. SPARK-1970 manual order indicator
2019-01-10 19:39:31 +00:00
Pedro Pinto 9838d123c7 Updated release notes. 2019-01-10 14:15:04 -05:00
Pedro Pinto 9d5b80c990 Forced manual order indicator to false on algos. 2019-01-10 14:12:27 -05:00
Taha Afzal 040fc3af96 removed the if _active_quoting check because that will always be the case 2019-01-10 09:47:45 -05:00
Kevin Darby 1c6333b07a now I have to figure out how to load the model 2019-01-09 18:15:04 -05:00
Taha Afzal cc07e28aca quoters, child orders and order builders are only created for quoting legs 2019-01-09 16:42:45 -05:00
Taha Afzal d2aec0c7f2 quoters are only created for quoting legs 2019-01-09 15:39:00 -05:00
Taha Afzal a71953b871 SPARK-1967 foundational work 2019-01-09 12:56:29 -05:00
Taha Afzal 70e962000f changed the ordering of member variables from lower mem to higher 2019-01-09 11:18:06 -05:00
Taha Afzal f413938943 broke h_p end log into ch_term and rep 2019-01-09 10:17:12 -05:00
Taha Afzal a7250b4734 SPARK-1959 _cache_warm_fill_ts is static now 2019-01-08 11:55:59 -05:00
Taha Afzal 060b88e4c9 SPARK-1959 largechunk done 2019-01-08 10:03:22 -05:00
Kevin Darby 26d543af82 long journey with externals 2019-01-08 09:57:53 -05:00
Kevin Darby 99b301ad6f statically linking tf with sparklib 2019-01-07 23:00:56 -05:00
Kevin Darby 9cbe83e1a4 keep tf out in the sdk land for a bit 2019-01-07 18:32:36 -05:00
Kevin Darby 59369e1b2b moving towards a tflow example 2019-01-07 17:54:39 -05:00
Kevin Darby 7c42e75ddd getting close 2019-01-04 18:14:53 -05:00
Jake Norbut ae200b374b PR suggestion 2019-01-04 12:38:56 -06:00
Jake Norbut 64b94c58e7 locking _resources ResourceDictionary prior to indexer access 2019-01-04 11:20:21 -06:00
Pedro Pinto 8e907d7395 Fixed perf_log.sql 2019-01-04 12:04:10 -05:00
Pedro Pinto c567283d3f More performance improvements on perf_log 2019-01-04 11:31:36 -05:00
Pedro Pinto 6b84dc433a Making log analysis faster. 2019-01-04 09:23:59 -05:00
Pedro Pinto a833944ec5 Improved perf log latency. 2019-01-03 19:07:18 -05:00
Kevin Darby b453be40fe strings... 2019-01-03 18:11:13 -05:00
Taha Afzal 97d16115e8 SPARK-1959 new order is constructed by the Hedger in init 2019-01-03 17:01:27 -05:00
Kevin Darby 96709c8121 ai algo sample 2019-01-03 16:20:15 -05:00
Taha Afzal 2e3957a7ac SPARK-1959 added get_new_hedger_order to ISpreaderManager 2019-01-03 15:18:53 -05:00
Taha Afzal b866157bff SPARK-1959 partially done 2019-01-03 14:24:33 -05:00
Michael Harding 8e9c7383b6 Merge branch 'master' into SPARK-1877-system-tests 2019-01-03 13:17:05 -05:00
Kevin Darby 5de9f63665 new proto36 2019-01-02 17:14:00 -05:00
John Colvin 930f3b23b8 Merged in SPARK-1903 (pull request #133)
RTM SPARK-1903 front end crash when sorting

Approved-by: Jake Norbut <jake.norbut@bluetradesys.com>
Approved-by: Eric Harding <eric.harding@bluetradesys.com>
2019-01-02 19:28:18 +00:00
Pedro Pinto d3fb52246c Merged 2019-01-02 19:24:23 +00:00
Pedro Pinto e173fe5515 Update release notes. 2019-01-02 19:23:35 +00:00
Pedro Pinto dbe02e44fd Merged in SPARK-1935-orderstate.display_status-doe (pull request #136)
RTM. Propagated display status through order state update event.
2019-01-02 19:13:24 +00:00
Jake Norbut 7453540140 Merged in SPARK-1918 (pull request #135)
RTM. SPARK-1918
2019-01-02 19:12:50 +00:00
Eric Harding 9830dcbe31 Merged in immutablefix (pull request #134)
RTM: It is not always safe to convert Foo to FooImmutable. It is always safe to convert it to Nullabke<FooImmutable>

Approved-by: Jake Norbut <jake.norbut@bluetradesys.com>
Approved-by: John Colvin <john.colvin@bluetradesys.com>
2019-01-02 19:11:38 +00:00
Eric Harding 69bc734b6a Merged in ReplayOptions (pull request #137)
RTM: Update spark replay defaults
2019-01-02 19:11:08 +00:00
Pedro Pinto 2e69966d44 Merged in SPARK-1954-make-sim-track-the-external-m (pull request #138)
RTM. Fixes sim drift awy from MD source.
2019-01-02 19:07:23 +00:00
Eric Harding c2070b8e52 CR feedback - immutables 2019-01-02 13:40:57 -05:00
Eric Harding 64e2408b59 It is not always safe to convert Foo to FooImmutable. It is always safe to convert it to Nullabke<FooImmutable> 2019-01-02 13:40:57 -05:00
Michael Harding 17a8d47452 Spark-1877: Add TestType to TestGroupAttribute 2019-01-02 13:40:57 -05:00
Taha Afzal b4eabf4eb8 cleaning up logs, and indentation 2019-01-02 13:37:56 -05:00
Taha Afzal f12c1d5e74 SPARK-1946 2019-01-02 12:28:16 -05:00
Pedro Pinto 714dfd5038 Fixes sim drift awy from MD source. 2019-01-02 17:05:38 +00:00
Eric Harding 6dfe9b3892 Add CoconutSecurityStatus to md tail 2019-01-01 10:50:05 -05:00
Eric Harding 15e557a209 Update cmakedeps 2019-01-01 10:49:41 -05:00
Eric Harding 8075bafb86 Update spark replay defaults 2018-12-31 13:07:18 -05:00
Taha Afzal e2f4a86fcf added tests to isolate the first hedge condition 2018-12-31 13:05:27 -05:00
Kevin Darby 6089b209d1 we want caffe2 in c++ not libtorch 2018-12-28 23:09:30 -05:00
Kevin Darby d7a12d0dd9 checkpoint 2018-12-28 17:40:32 -05:00
Pedro Pinto 95ae7b780e Propagated display status through order state update event. 2018-12-27 21:35:18 +00:00
Taha Afzal 0644d301b2 merging from master 2018-12-27 13:24:48 -05:00
Jake Norbut 7e68dc4ff7 fixing tabs in notes 2018-12-26 13:58:03 -06:00
Jake Norbut 879963b828 updating release notes 2018-12-26 13:55:38 -06:00
Jake Norbut 5320e16088 commenting out anything having to do w/ window width and height since that interaction is still mysterious; fixing scale factor restortation 2018-12-26 11:02:07 -06:00
Taha Afzal 6116e24df0 added comments to hedger, and formatted 2018-12-25 23:50:26 -05:00
Taha Afzal 6ba1de8c5c changing order_key name 2018-12-25 10:31:35 -05:00
Taha Afzal 0d66054e8e dealing with the Hedger._key() for hedgers with no working orders 2018-12-24 15:11:40 -05:00
Taha Afzal daf39324fd merging 2018-12-24 12:45:02 -05:00
Taha Afzal ab9d3cede3 odified some test code 2018-12-24 09:14:22 -05:00
Kevin Darby 2f87fe31be mlpack 2018-12-21 18:25:19 -05:00
Jake Norbut 7429c42de2 checking this in b/c i've lost things too many times keeping stuff in the stash and switching branches; this is just really testing, no sln yet regarding window borders 2018-12-21 16:24:57 -06:00
Jake Norbut 9147b4605a adding zoom_factor to window_specifics 2018-12-21 16:21:34 -06:00
Kevin Darby 5a9749d551 testing this out in the sdk 2018-12-21 17:17:18 -05:00
Kevin Darby ea950c8786 pushed by mistake 2018-12-21 17:05:24 -05:00
Jake Norbut 6fc8a6c7fe Merge branch 'master' of bitbucket.org:bluetradesys/spark into SPARK-1918 2018-12-21 16:02:08 -06:00
Kevin Darby 30891bfb49 need a little boost 2018-12-21 15:28:45 -05:00
John Colvin 8a4d3d4c97 SPARK-1903 CR - unit test for SortedTree.TryReplace, comments in
OrderBookRowCollection
2018-12-21 12:25:01 -06:00
Eric Harding 7cbf0dc683 CR feedback - immutables 2018-12-21 10:38:56 -05:00
Eric Harding e05ce79abf It is not always safe to convert Foo to FooImmutable. It is always safe to convert it to Nullabke<FooImmutable> 2018-12-20 20:30:10 -05:00
John Colvin 2ea95e7938 SPARK-1903 front end crash when sorting 2018-12-20 16:15:54 -06:00
Taha Afzal 641141810e Cleaned up HedgerPriceQuantity 2018-12-20 17:07:52 -05:00
Kevin Darby 34319c4536 Merge branch 'master' of bitbucket.org:bluetradesys/spark into algos2 2018-12-20 16:10:58 -05:00
Taha Afzal c3ac2957d2 added comments to SpreaderChildOrder and cleaned it up a bit 2018-12-20 10:05:07 -05:00
Kevin Darby 196c518ac6 remove tick order 2018-12-20 09:43:44 -05:00
Kevin Darby f04af5af9d fix build 2018-12-20 09:39:05 -05:00
Taha Afzal 950509e5d6 added new hedger behaviour (recycle) test 2018-12-19 18:58:18 -05:00
Kevin Darby 8f4da463a7 Merge branch 'master' of bitbucket.org:bluetradesys/spark into algos2 2018-12-19 18:24:14 -05:00
Kevin Darby f3adf780d0 OCOOrder will be the basis of a StopLoss template
Added the beginnings of pricer order but need something from John
2018-12-19 18:15:04 -05:00
Taha Afzal 9002ca6183 some hedger interface cleanup, and tst code 2018-12-19 09:20:54 -05:00
Taha Afzal b36715a6a0 fixing build 2018-12-18 15:57:53 -05:00
Taha Afzal 2305c3af32 removed the vector access ot hedger 2018-12-18 15:42:39 -05:00
Jake Norbut 6259f8b03f fixing build 2018-12-18 10:53:52 -06:00
Jake Norbut 3866e63a70 merging master and fixing 2018-12-18 10:53:23 -06:00
Pedro Pinto 5078b74f72 Dev doc 2018-12-18 09:22:12 -05:00
Taha Afzal 6a1a2d5f0a organizing around HegderManager 1 2018-12-18 07:12:33 -05:00
Kevin Darby 664c1f28ed Merge branch 'master' of bitbucket.org:bluetradesys/spark into algos2 2018-12-17 18:05:59 -05:00
Kevin Darby aae927d773 gui for new algos 2018-12-17 17:38:22 -05:00
Taha Afzal b90f6cb45c all spreader unit tests restored 2018-12-17 16:50:35 -05:00
Taha Afzal 1cc5a77d7f more tests enabled 2018-12-17 16:39:50 -05:00
Taha Afzal fb14a9c3af restoring tests 2018-12-17 16:17:08 -05:00
Kevin Darby 00dba92636 Merge branch 'master' of bitbucket.org:bluetradesys/spark into algos2 2018-12-17 15:36:32 -05:00
Taha Afzal e82db39f8c merging from SPARK-1887-speed-up-order-manager 2018-12-17 14:45:54 -05:00
Kevin Darby 5a5de65292 OCO and Pricer Algos 2018-12-17 13:56:24 -05:00
Taha Afzal dffb9c5320 guard around SpreaderChildOrder::order_key() to deal with in active state 2018-12-17 11:34:48 -05:00
Taha Afzal 2be4eb1c5c adding is_permenantly_cancelled to hedger 2018-12-16 22:15:39 -05:00
Taha Afzal 175204efdf removed the init call from Hedger 2018-12-14 17:50:44 -05:00
Jake Norbut dbd8a7d742 Zoom - proto, settings, UI 2018-12-14 15:06:40 -06:00
Taha Afzal 8894aea1ad removed the hedge vector from SpreaderBookkeepingData 2018-12-14 13:42:05 -05:00
Taha Afzal 43e82fb8c4 Added HedgerManager that keeps track of activ hedgers 2018-12-13 22:04:56 -05:00
209 changed files with 7282 additions and 2376 deletions

No files matched your search

+3
View File
@@ -30,6 +30,7 @@
"${workspaceRoot}/build/ninja_debug/src",
"${workspaceRoot}/externals/windows/include",
"${workspaceRoot}/externals/linux/include",
"${workspaceRoot}/externals/linux/include/tensorflow/contrib/makefile/gen/proto",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6/backward",
@@ -50,6 +51,7 @@
"${workspaceRoot}/build/ninja_debug/src",
"${workspaceRoot}/externals/windows/include",
"${workspaceRoot}/externals/linux/include",
"${workspaceRoot}/externals/linux/include/tensorflow/contrib/makefile/gen/proto",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6/backward",
@@ -74,6 +76,7 @@
"${workspaceRoot}/build/ninja_debug/src",
"${workspaceRoot}/externals/windows/include",
"${workspaceRoot}/externals/linux/include",
"${workspaceRoot}/externals/linux/include/tensorflow/contrib/makefile/gen/proto",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6/backward",
+43 -3
View File
@@ -6,7 +6,7 @@
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceRoot}/build/ninja_debug/src/server/sparkd/sparkd",
"program": "${workspaceRoot}/build/ninja_debug/server/sparkd/sparkd",
"args": ["run"],
"stopAtEntry": false,
"cwd": "${workspaceRoot}/build/ninja_debug/src/server/sparkd",
@@ -75,10 +75,10 @@
"name": "SparkVM Launch",
"type": "cppdbg",
"request": "launch",
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
"program": "/home/bts/spark/build/ninja_debug/server/sparkd",
"args": ["run"],
"stopAtEntry": false,
"cwd": "/home/bts/spark/build/ninja_debug/src/server/sparkd/",
"cwd": "/home/bts/spark/build/ninja_debug/server/",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
@@ -108,6 +108,46 @@
"/home/bts/spark/": "${workspaceRoot}"
}
},
{
"name": "TFTest ",
"type": "cppdbg",
"request": "launch",
"program": "/home/bts/spark/build/ninja_debug/sdk/examples/tf_test",
"args": [
],
"stopAtEntry": false,
"cwd": "/home/bts/spark/build/ninja_debug/sdk/examples/",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"preLaunchTask": "",
"logging": {
"engineLogging": false
},
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "enable pretty-printer",
"ignoreFailures": true
},
{
"description": "Skip STL",
"text": "skip -gfi /usr/include/c++/7/bits/*.h",
"ignoreFailures": true
}
],
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
"pipeArgs": [
"bts@sparkvm"
],
"debuggerPath": "/usr/bin/gdb"
},
"sourceFileMap": {
"/home/bts/spark/": "${workspaceRoot}"
}
},
{
"name": "Spreader Tests",
"type": "cppdbg",
+4 -1
View File
@@ -13,7 +13,7 @@ set (SPARK_BIN "${EXTERNALS_ROOT}/bin")
set (SPARK_INCLUDE "${EXTERNALS_ROOT}/include")
set (SPARK_LIB "${EXTERNALS_ROOT}/lib/${CMAKE_BUILD_TYPE}")
include_directories (BEFORE SYSTEM ${SPARK_INCLUDE} ${EXTERNALS_ROOT}/include/zlib)
include_directories (BEFORE SYSTEM ${SPARK_INCLUDE} ${EXTERNALS_ROOT}/include/zlib ${TF_INCLUDE})
link_directories (${SPARK_LIB})
if (WIN32)
@@ -57,6 +57,9 @@ else ()
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/
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/sdk/examples/ai_order_plugin_example.so ${CMAKE_BINARY_DIR}/server/plugins/
COMMAND ln ARGS -sf ${EXTERNALS_ROOT}/lib/Release/libtensorflow.so ${CMAKE_BINARY_DIR}/server/plugins
COMMENT "Creating server runtime layout"
DEPENDS sparkd data_files_dir)
+35 -37
View File
@@ -1,11 +1,10 @@
# The BTS Development Process #
## The Big Picture ##
Our development work is organized in projects. A project is an effort
to specifiy, develop and validate a related set of additions to our
Spark platform. A project can be assigned to one more developers and a
developer might concurrently be assigned to multiple
## Projects ##
Our development work is organized in projects. A project is a
non-trivial effort to specify, develop and validate a related set of
additions to our Spark platform. A project can be assigned to one more
developers and a developer might concurrently be assigned to multiple
projects. Projects typically start out with specification work,
proceed to implementation and finish with validation efforts. At any
given time there will be multiple projects being worked on
@@ -14,16 +13,16 @@ are merged into the product and deployed to customers.
## The Details ##
Typically project ideas come from sales interactions, opposition
research and customer feedback, alltough on occasion development or
operational requirements will also suggest potentially valuable
research and customer feedback, all tough on occasion development or
operational requirements can also suggest valuable project
ideas. Whatever the source of a project idea the final decision of
which projects to pursue is always done by management. Once a project
idea has been selected for implementation the corresponding project
will go through several phases: inception, specification, development
and merge. We detail each of these phases below.
will go through several phases: inception, specification, development,
validation and merge.
* Inception. In this phase we create the infrastructure for the
project. Typically this means selecting a team, creating a project
* Inception. In this phase the infrastructure for the project is
created. Typically this means selecting a team, creating a project
case in Jira (that is a case assigned to the team@bluetradesys.com
Jira user) and possibly creating a new branch for the project. This
phase is mostly mechanical and the responsibility of Pedro.
@@ -32,11 +31,11 @@ phase is mostly mechanical and the responsibility of Pedro.
ill-considered idea project idea into a concrete, implementable
specification that attempts to maximize the value/cost ratio of the
project. It is hard to exaggerate the impact of a this phase on the
rest of the project. *Nothing* has more impact on our ability to
quickly deliver value to customers than good specification
work. Specification typically take the form of shared google docs,
using a mix of text and UI mockups to capture both user requirements
and suggested implementation strategies. Taha is responsible for this
rest of the project. *Nothing* has more impact on BTS's ability to
quickly deliver value to customers than good specification work. A
specification typically takes the form of a shared google docs using
a mix of text and UI mock-ups to capture both user requirements and
suggested implementation strategies. Taha and Kevin are responsible for this
phase.
* Development. Once a specification is complete, a team of developers
@@ -44,24 +43,26 @@ will use a project specific branch to implement the
specification. Periodically, typically once a week, progress on the
project is assessed by Pedro, possibly with the help of others. This
assessment takes the form of code reviews, demos, or just one-on-one
conversations. To ensure development does not go off on sub-optimal
tangents, developers are expected to continuously merge master into
the project branch as well as encouraged to create Pull Requests (PRs)
early in the project implementation, so that their work is kept
visible and integrated with that of the rest of the group. During the
conversations. To ensure development does not go off on tangents,
developers are expected to continuously merge master into the project
branch as well as encouraged to create Pull Requests (PRs) early in
the project implementation, so that their work is kept visible and
integrated with that of the rest of the group. During the
implementation phase developers should reach out to Pedro for UI
reviews, architecture and design concerns as well as specification
trade off concerns.
reviews, architecture and design questions and specification trade off
concerns.
* Verification. Once code is complete think carefully about the best way
to verify that it is good before it goes to production. We don't have a
dedicated QA cycle to flush out bugs so it's important that a change be
fully tested before it's marked "Ready to Merge." For any non-trivial
change consider enlisting a 'test buddy' to help review the code and
think of test cases that you may not have considered. Stability from
release to release is especially critical right now as we develop a
reputation in the futures world.
- Code Reviews
* Verification. Once code is complete it is the project's team job to
think carefully about the best way to verify that the work is solid
enough to go to production. We do not have a dedicated QA cycle to
flush out bugs so it is important for changes to be fully tested
before being marked ready to merge (RTM). For any non-trivial change
project teams should enlist a 'test buddy' from outside the team to
help review the code and think of test cases that they may not have
considered. Stability from release to release is especially critical
right now as we develop a reputation in the futures
world. Additionally, project teams are encouraged to make liberal use
of other testing techniques such as
- Unit tests
- System tests
- Manual tests
@@ -70,7 +71,7 @@ reputation in the futures world.
that includes Pedro should be created (unless, as mentioned above, an
early PR was already created in the development phase). Whether the PR
already existed or not, its description should be changed to start
with the "Ready To Merge" statement. This marks the project as ready
with the RTM (Ready To Merge) acronym. This marks the project as ready
to be merged into master. Once a week, typically on Mondays, Pedro
will go through every PR marked as "Ready To Merge", build it, check
it out and if everything looks good merge it to master. At the end of
@@ -79,6 +80,3 @@ number. This version will be go through some additional testing by
Brian and will then be deployed by Karl and Pete to customers
throughout the rest of the week.
## Tools ##
* Pre-Merge checklist
* Code Review tutorial
+68
View File
@@ -1,4 +1,72 @@
# Release Notes
## 1.5.0
### User Visible Changes
#### User Interface Improvements
- Removed security key field from most grids
- Removed trade key field from time and sales grid
- Fixed the "Since Open" time filter to use the exchange open time rather than 8:30 AM
- Fixed the floating order book so that rows are no longer
highlighted after an order is modified
#### SDK
- Improved SDK documentation and usability
### Internal Changes
- Improved robustness of limit system test
- Extensive market data refactoring allow for security definition updates
## 1.4.11
### New Features
- Floating Order Book
- The floating order book provides a quick view of orders occupying a price level in the ladder
- Launch the Floating Order Book by middle-clicking a ladder badge
- Cancel orders by clicking on the red X in the Cancel column
- Quantity and Price modification
- Clicking on a row will select it, providing the option for changing your price and quantity
- Enter in a new value or use the up/down buttons to set a desired value
- Press the green checkbox to finalize your change and update the order
### SDK
- Improved SDK documentation and usability
### User Interface Improvements
- The following spreader quoting parameters have been deprecated:
- Hidden parameter
- Price Type setting of the Conditional parameter
### Bug Fixes
- Fixed a limit enforcement problem that could lead to 0 sized orders being sent to the exchange
## 1.4.10
### Bug Fixes
- Removed duplicate entries in performance log
## 1.4.9
### SDK
- Added ticker events to the order API
### Performance Improvements
- Significantly improved hedging speed
### Bug Fixes
- Fixed a visual oddity in the order book UI when using High DPI displays
## 1.4.8
### Marketdata
- Additional trade details for CME ticker
## 1.4.7
### Bug Fixes
- Corrected FIX tag 1028, ManualOrderIndicator, when orders are triggered by algos
## 1.4.6
### Ladder Usability Improvements
- The ladder can now be zoomed in/out according to a user's preference
- The zoom slider can be enabled from Ladder Form -> Settings button -> Left Pane tab -> check Zoom Slider checkbox
- The zoom functionality can also be performed via hotkey and mouse wheel combinations
- Zoom In = CTRL + Mouse wheel up
- Zoom Out = CTRL + Mouse wheel down
- Reset zoom = CTRL + Mouse wheel click or double click on the zoom slider
### Exchange simulator
- Improved the exchange simulator to track real market data more closely
### Bug Fixes
- Fixed a UI crash in some cases when attempting to sort the order book by time
## 1.4.5
- Fixed entitlement validation for ICS spreads
- Tuned performance logging
+27
View File
@@ -0,0 +1,27 @@
{
"folders": [
{
"path": "."
},
{
"uri": "sftp://bts:BT5u53r@sparkvm:22/home/bts/",
"name": "sparkvm"
}
],
"settings": {
"files.associations": {
"utility": "cpp",
"initializer_list": "cpp",
"list": "cpp",
"type_traits": "cpp",
"vector": "cpp",
"xhash": "cpp",
"xstring": "cpp",
"system_error": "cpp",
"array": "cpp",
"string_view": "cpp",
"xutility": "cpp",
"*.ipp": "cpp"
}
}
}
+77
View File
@@ -0,0 +1,77 @@
{
"folders": [
{
"path": "."
}
],
"settings": {
"files.associations": {
"utility": "cpp",
"initializer_list": "cpp",
"list": "cpp",
"type_traits": "cpp",
"vector": "cpp",
"xhash": "cpp",
"xstring": "cpp",
"system_error": "cpp",
"array": "cpp",
"string_view": "cpp",
"xutility": "cpp",
"*.ipp": "cpp",
"atomic": "cpp",
"hash_map": "cpp",
"hash_set": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"cfenv": "cpp",
"chrono": "cpp",
"cinttypes": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"complex": "cpp",
"condition_variable": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"exception": "cpp",
"any": "cpp",
"optional": "cpp",
"fstream": "cpp",
"functional": "cpp",
"future": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"memory": "cpp",
"mutex": "cpp",
"new": "cpp",
"ostream": "cpp",
"numeric": "cpp",
"ratio": "cpp",
"scoped_allocator": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"tuple": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"valarray": "cpp",
"variant": "cpp"
}
}
}
+7 -2
View File
@@ -31,7 +31,9 @@ namespace mbts.ui {
}
private static ImageSource load_resource_and_freeze(string resource_name) {
return ((DrawingImage)_resources[resource_name]).frozen();
lock (_resources) {
return ((DrawingImage)_resources[resource_name]).frozen();
}
}
#pragma warning disable CS0618 // Type or member is obsolete
@@ -152,7 +154,10 @@ namespace mbts.ui {
}
static IEnumerable<string> _get_geometric_path(string geometric_path_key) {
object obj = _resources[geometric_path_key];
object obj;
lock (_resources) {
obj = _resources[geometric_path_key];
}
if (obj is string path) {
if (string.IsNullOrEmpty(path)) {
Log.Api.error($"Resource lookup of '{geometric_path_key}' did not return a valid string.", nameof(geometric_path_key));
@@ -210,36 +210,28 @@ namespace mbts.spark {
var order = _orders_model.factory.order(security);
switch (col) {
case MarketViewView.Columns.Bid:
order.Side = Side.Sell;
_bus.post(SparkTags.ShowOrderTicketTag, (order, bid_price, 0u));
_bus.post(SparkTags.ShowOrderTicketTag, (order.with(side:Side.Sell), bid_price, 0u));
break;
case MarketViewView.Columns.BidMergedSize:
order.Side = Side.Sell;
_bus.post(SparkTags.ShowOrderTicketTag, (order, bid_price, bid_merged_size));
_bus.post(SparkTags.ShowOrderTicketTag, (order.with(side:Side.Sell), bid_price, bid_merged_size));
break;
case MarketViewView.Columns.BidDirectSize:
order.Side = Side.Sell;
_bus.post(SparkTags.ShowOrderTicketTag, (order, bid_price, bid_direct_size));
_bus.post(SparkTags.ShowOrderTicketTag, (order.with(side:Side.Sell), bid_price, bid_direct_size));
break;
case MarketViewView.Columns.BidImpliedSize:
order.Side = Side.Sell;
_bus.post(SparkTags.ShowOrderTicketTag, (order, bid_price, bid_implied_size));
_bus.post(SparkTags.ShowOrderTicketTag, (order.with(side:Side.Sell), bid_price, bid_implied_size));
break;
case MarketViewView.Columns.Ask:
order.Side = Side.Buy;
_bus.post(SparkTags.ShowOrderTicketTag, (order, ask_price, 0u));
_bus.post(SparkTags.ShowOrderTicketTag, (order.with(side:Side.Buy), ask_price, 0u));
break;
case MarketViewView.Columns.AskMergedSize:
order.Side = Side.Buy;
_bus.post(SparkTags.ShowOrderTicketTag, (order, ask_price, ask_merged_size));
_bus.post(SparkTags.ShowOrderTicketTag, (order.with(side:Side.Buy), ask_price, ask_merged_size));
break;
case MarketViewView.Columns.AskDirectSize:
order.Side = Side.Sell;
_bus.post(SparkTags.ShowOrderTicketTag, (order, ask_price, ask_direct_size));
_bus.post(SparkTags.ShowOrderTicketTag, (order.with(side:Side.Sell), ask_price, ask_direct_size));
break;
case MarketViewView.Columns.AskImpliedSize:
order.Side = Side.Sell;
_bus.post(SparkTags.ShowOrderTicketTag, (order, ask_price, ask_implied_size));
_bus.post(SparkTags.ShowOrderTicketTag, (order.with(side:Side.Sell), ask_price, ask_implied_size));
break;
case MarketViewView.Columns.Last:
_bus.post(SparkTags.ShowOrderTicketTag, (order, last_price, 0u));
@@ -96,7 +96,7 @@ namespace bts.shell {
public static GridColumnSettings day_change => new GridColumnSettings(col_id(Columns.DayChange), DefaultColumnHeaders.DayChange, width: DefaultColumnWidths.Price, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
public static GridColumnSettings session_low => new GridColumnSettings(col_id(Columns.SessionLow), DefaultColumnHeaders.SessionLow, width: DefaultColumnWidths.Price, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
public static GridColumnSettings session_high => new GridColumnSettings(col_id(Columns.SessionHigh), DefaultColumnHeaders.SessionHigh, width: DefaultColumnWidths.Price, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
public static GridColumnSettings security_key => new GridColumnSettings(col_id(Columns.SecurityKey), DefaultColumnHeaders.SecurityKey, width: DefaultColumnWidths.SecurityKey);
public static GridColumnSettings security_key => new GridColumnSettings(col_id(Columns.SecurityKey), DefaultColumnHeaders.SecurityKey, is_visible: false, width: DefaultColumnWidths.SecurityKey);
@@ -97,8 +97,11 @@ namespace mbts.spark {
public IEnumerable<TradeInfo> read_trades() {
var copy = _securities;
foreach (var tm in _channel.read_trades(ref _cursor)) {
if (copy.TryGetValue(tm.Key, out SecurityImmutable sec))
yield return new TradeInfo(sec, tm);
if (tm != null) {
if (copy.TryGetValue(tm.Key, out SecurityImmutable sec)) {
yield return new TradeInfo(sec, new TradeMessageImmutable(tm));
}
}
}
}
}
@@ -38,7 +38,6 @@ namespace mbts.spark {
price_filter.load_state(filters.price);
size_filter.load_state(filters.size);
aggressor_filter.load_state(filters.aggressor_sides);
trade_key_filter.load_state(filters.trade_key);
security_key_filter.load_state(filters.security_key);
}
// Columns
@@ -47,7 +46,6 @@ namespace mbts.spark {
add_column(TimeAndSalesView.Columns.Price, DefaultColumnHeaders.Price, DefaultColumnWidths.Price, nameof(Row.price), price_filter, DataGridFilterKnownTemplates.DoubleMinMax, System.Windows.HorizontalAlignment.Right);
add_column(TimeAndSalesView.Columns.Size, DefaultColumnHeaders.Size, DefaultColumnWidths.Size, nameof(Row.size), size_filter, DataGridFilterKnownTemplates.UIntMinMax, System.Windows.HorizontalAlignment.Right);
add_column(TimeAndSalesView.Columns.Aggressor, DefaultColumnHeaders.Aggressor, DefaultColumnWidths.Aggressor, nameof(Row.aggressor_side), aggressor_filter, DataGridFilterKnownTemplates.EnumValues);
add_column(TimeAndSalesView.Columns.TradeKey, DefaultColumnHeaders.TradeKey, DefaultColumnWidths.TradeKey, nameof(Row.trade_key), trade_key_filter, DataGridFilterKnownTemplates.Regex);
add_column(TimeAndSalesView.Columns.SecurityKey, DefaultColumnHeaders.SecurityKey, DefaultColumnWidths.SecurityKey, nameof(Row.security_key), security_key_filter, DataGridFilterKnownTemplates.Regex);
void add_column(TimeAndSalesView.Columns col_key, string header, double width, string sort_member_path, IDataGridColumnFilter filter, string filter_template, System.Windows.HorizontalAlignment h_alignment = System.Windows.HorizontalAlignment.Left) =>
columns.Add(new TimeAndSalesColumn(
@@ -66,7 +64,7 @@ namespace mbts.spark {
_resources.AddRange(
show_ladder,
DataGridFilterHelper.hook_filters(
rows_view, time_filter, security_filter, price_filter, size_filter, aggressor_filter, trade_key_filter, security_key_filter),
rows_view, time_filter, security_filter, price_filter, size_filter, aggressor_filter, security_key_filter),
settings_manager.subscribe_current().OnDispatcher().Subscribe(grid_settings_manager)
);
rows_view.set_sort_descriptions(startup_data.sorting_criterion, columns);
@@ -103,7 +101,6 @@ namespace mbts.spark {
public IDataGridColumnPersistentFilter<Row, UIntMinMaxState> size_filter { get; } = new UIntMinMax<Row>(r => r.size, nameof(Row.size));
public IDataGridColumnPersistentFilter<Row, AggressorSide[]> aggressor_filter { get; } = DiscreteValuesFilterVM.Create<Row, AggressorSide>(EnumHelper.get_values<AggressorSide>().ToArray(), r => r.aggressor_side, nameof(Row.aggressor_side));
public IDataGridColumnPersistentFilter<Row, string> security_key_filter { get; } = new RegexFilterVM<Row>(r => r.security_key.ToString(), nameof(Row.security_key));
public IDataGridColumnPersistentFilter<Row, string> trade_key_filter { get; } = new RegexFilterVM<Row>(r => r.trade_key.ToString(), nameof(Row.trade_key));
FilterStates _get_filter_states() =>
new FilterStates {
@@ -111,7 +108,6 @@ namespace mbts.spark {
security = security_filter.get_state(),
price = price_filter.get_state(),
size = size_filter.get_state(),
trade_key = trade_key_filter.get_state(),
security_key = security_key_filter.get_state(),
aggressor_sides = aggressor_filter.get_state()
};
@@ -175,7 +171,6 @@ namespace mbts.spark {
case TimeAndSalesView.Columns.Price: return _price_text;
case TimeAndSalesView.Columns.Size: return _size_text;
case TimeAndSalesView.Columns.Aggressor: return _aggressor_text;
case TimeAndSalesView.Columns.TradeKey: return _trade_key_text;
case TimeAndSalesView.Columns.SecurityKey: return _security_key_text;
default: return null;
}
@@ -7,7 +7,7 @@ namespace mbts.ui.spark {
/// Interaction logic for TimeAndSalesView.xaml
/// </summary>
partial class TimeAndSalesView : UserControl {
public enum Columns { Time, Security, Price, Size, OrderType, TradeKey, SecurityKey, Aggressor }
public enum Columns { Time, Security, Price, Size, OrderType, SecurityKey, Aggressor }
public TimeAndSalesView() =>
InitializeComponent();
@@ -84,8 +84,7 @@ namespace bts.shell {
public static GridColumnSettings price => new GridColumnSettings(col_id(Columns.Price), DefaultColumnHeaders.Price, width: DefaultColumnWidths.Price, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
public static GridColumnSettings size => new GridColumnSettings(col_id(Columns.Size), DefaultColumnHeaders.Size, width: DefaultColumnWidths.Size, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
public static GridColumnSettings aggressor => new GridColumnSettings(col_id(Columns.Aggressor), DefaultColumnHeaders.Aggressor, width: DefaultColumnWidths.Aggressor);
public static GridColumnSettings trade_key => new GridColumnSettings(col_id(Columns.TradeKey), DefaultColumnHeaders.TradeKey, width: DefaultColumnWidths.TradeKey);
public static GridColumnSettings security_key => new GridColumnSettings(col_id(Columns.SecurityKey), DefaultColumnHeaders.SecurityKey, width: DefaultColumnWidths.SecurityKey);
public static GridColumnSettings security_key => new GridColumnSettings(col_id(Columns.SecurityKey), DefaultColumnHeaders.SecurityKey, is_visible:false, width: DefaultColumnWidths.SecurityKey);
public static IEnumerable<SortingCriteria> default_sorting_criterion {
get {
@@ -100,7 +99,6 @@ namespace bts.shell {
yield return price;
yield return size;
yield return aggressor;
yield return trade_key;
yield return security_key;
}
}
@@ -117,8 +115,8 @@ namespace bts.shell {
public DoubleMinMaxState price;
[ProtoMember(4)]
public UIntMinMaxState size;
[ProtoMember(5)]
public string trade_key;
// [ProtoMember(5)]
// ProtoMember 5 cannot be used further
[ProtoMember(6)]
public string security_key;
[ProtoMember(7)]
@@ -53,8 +53,8 @@ namespace mbts.spark {
return null;
}
public async Task<uint?> create_synthetic(SecurityImmutable synthetic) {
var result = await _service.create_synthetic_async(synthetic);
public async Task<uint?> create_synthetic(SecurityImmutable? synthetic) {
var result = await _service.create_synthetic_async(synthetic.Value);
return _error.handle_error(result, "Error creating synthetic: {0}", r => r.Error, e => e == CreateResult.Types.Error.Ok, r => new uint?(r.Key), () => null).result;
}
@@ -66,7 +66,7 @@ namespace bts.shell {
public static GridColumnSettings description => new GridColumnSettings(col_id(Columns.Description), DefaultColumnHeaders.Description, width: DefaultColumnWidths.Description);
public static GridColumnSettings n_legs => new GridColumnSettings(col_id(Columns.n_legs), DefaultColumnHeaders.N_Legs, width: DefaultColumnWidths.N_Legs);
public static GridColumnSettings n_working_orders => new GridColumnSettings(col_id(Columns.n_working_orders), DefaultColumnHeaders.N_Working_Orders, width: DefaultColumnWidths.N_Working_Orders);
public static GridColumnSettings security_key => new GridColumnSettings(col_id(Columns.SecurityKey), DefaultColumnHeaders.SecurityKey, width: DefaultColumnWidths.SecurityKey);
public static GridColumnSettings security_key => new GridColumnSettings(col_id(Columns.SecurityKey), DefaultColumnHeaders.SecurityKey, is_visible: false, width: DefaultColumnWidths.SecurityKey);
public static IEnumerable<SortingCriteria> default_sorting_criterion {
get {
@@ -205,7 +205,7 @@ namespace mbts.spark {
//new EnableHedgeModel(), //TAHA_SPREADER
new HedgeRatioModel(),
//new MinLeanQtyModel(), //TAHA_SPREADER
new QuoteHiddenModel(),
//new QuoteHiddenModel(),
new MarketDataTypeModel(),
new MarketDataCalculationModel(),
new QuoteThrottleEnabledModel(quote_throttle_inside_ticks, quote_throttle_outside_ticks),
@@ -213,7 +213,7 @@ namespace mbts.spark {
quote_throttle_outside_ticks,
new ConditionalQuoteEnabledModel(conditional_quoting_ticks, conditional_quoting_price_type),
conditional_quoting_ticks,
conditional_quoting_price_type,
//conditional_quoting_price_type,
//new QuoteInsideMarketThrottleEnabledModel(quote_inside_market_throttle_ticks, quote_inside_market_throttle_min_move),
//quote_inside_market_throttle_ticks,
//quote_inside_market_throttle_min_move,
@@ -294,9 +294,9 @@ namespace mbts.spark {
base.Dispose(disposing);
}
static string _deduce_symbol(SecurityImmutable security) {
if (!string.IsNullOrWhiteSpace(security.Symbol)) return security.Symbol;
if (security.Synthetic.Legs.Count() > 0) return security.Synthetic.Legs.First().Security.Symbol;
static string _deduce_symbol(SecurityImmutable? security) {
if (!string.IsNullOrWhiteSpace(security?.Symbol)) return security?.Symbol;
if (security?.Synthetic.Legs.Count() > 0) return security?.Synthetic.Legs.First().Security.Symbol;
return string.Empty;
}
@@ -178,7 +178,7 @@ namespace mbts.spark {
} else return model.on_fill_tuples;
}
static IConnectableObservable<IIncrementalUpdate<FillTuple, FillTupleKey>> _get_observable(IBus bus, OrdersModel model, IObservable<StartupData> state) =>
static IConnectableObservable<IIncrementalUpdate<FillTuple, FillTupleKey>> _get_observable(IBus bus, OrdersModel model, IObservable<StartupData> state) =>
state.SelectManyInSeries(s => _get_observable(bus, model, s));
public class Row : SecurityRow, IEquatable<Row>, IRowVM {
@@ -186,7 +186,7 @@ namespace mbts.spark {
readonly FillImmutable _fill;
readonly OrderRecordImmutable _order;
public Row(FillTuple fill_tuple, OrdersModel model) : base(fill_tuple.security_md.HasValue ? fill_tuple.security_md.Value.security : SecurityDataHelper.Defaults.Security) {
public Row(FillTuple fill_tuple, OrdersModel model) : base(fill_tuple.security_md.HasValue ? fill_tuple.security_md.Value.security : SecurityDataHelper.Defaults.SecurityImmutable) {
_fill = fill_tuple.fill;
_order = fill_tuple.order ?? OrderDataHelper.Defaults.OrderRecordImmutable;
_model = model;
@@ -86,7 +86,7 @@ namespace bts.shell {
public static GridColumnSettings fill_kind => new GridColumnSettings(col_id(Columns.FillKind), DefaultColumnHeaders.FillKind, width: DefaultColumnWidths.FillKind);
public static GridColumnSettings fill_key => new GridColumnSettings(col_id(Columns.FillKey), DefaultColumnHeaders.FillKey, width: DefaultColumnWidths.FillKey);
public static GridColumnSettings order_key => new GridColumnSettings(col_id(Columns.OrderKey), DefaultColumnHeaders.OrderKey, width: DefaultColumnWidths.OrderKey);
public static GridColumnSettings security_key => new GridColumnSettings(col_id(Columns.SecurityKey), DefaultColumnHeaders.SecurityKey, width: DefaultColumnWidths.SecurityKey);
public static GridColumnSettings security_key => new GridColumnSettings(col_id(Columns.SecurityKey), DefaultColumnHeaders.SecurityKey, is_visible: false, width: DefaultColumnWidths.SecurityKey);
public static IEnumerable<SortingCriteria> default_sorting_criterion {
get {
yield return new SortingCriteria(fill_time.id, false);
@@ -0,0 +1,166 @@
<!-- MaxHeight will force only x rows before vertical scrollbar shows up -->
<!-- MinWidth will give enough room beyond the last column so that the the verical scrollbar does not eclipse the column content -->
<UserControl x:Class="mbts.spark.MiniOrderBookView" x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:sp="clr-namespace:mbts.spark"
xmlns:uc="clr-namespace:mbts.ui"
xmlns:c="clr-namespace:mbts.ui.controls"
xmlns:usp="clr-namespace:mbts.ui.spark"
xmlns:uspcv="clr-namespace:mbts.ui.spark.converters"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:order="clr-namespace:bts.api.orderman;assembly=spark_api"
mc:Ignorable="d"
MaxHeight="240"
MinWidth="875"
d:DesignHeight="600" d:DesignWidth="1080"
FocusManager.IsFocusScope="True"
Background="{StaticResource CommonBackground}">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/view/Controls/DataGridEx/Filters/Views/FilterTemplates.xaml"/>
</ResourceDictionary.MergedDictionaries>
<uspcv:TickDisplayConverter x:Key="TickDisplayConverter"/>
<uspcv:OrderSubTypeDisplayTextConverter x:Key="OrderSubTypeLongDisplayTextConverter" UseLongName="True" />
<DataTemplate x:Key="{x:Static sp:MiniOrderBookView.SubTypeFilterTemplateKey}">
<usp:FilterContentControl
ApplyCommandParameter="{Binding}"
ApplyCommand="{x:Static c:DataGridFilterProperties.CommitCommand}"
ClearCommandParameter="{Binding}"
ClearCommand="{x:Static c:DataGridFilterProperties.ClearCommand}"
>
<c:ListBoxEx
ItemsSource="{Binding items}"
Selection="{Binding selected_items}"
SelectionMode="Multiple"
ItemContainerStyle="{StaticResource ListBoxItemCheckBoxStyle}"
>
<c:ListBoxEx.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource OrderSubTypeLongDisplayTextConverter}}"/>
</DataTemplate>
</c:ListBoxEx.ItemTemplate>
</c:ListBoxEx>
</usp:FilterContentControl>
</DataTemplate>
<Style x:Key="{x:Static sp:MiniOrderBookView.RowStyleKey}" TargetType="ListBoxItem" BasedOn="{StaticResource DIYGridRowStyle}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="False"/>
<Condition Binding="{Binding status}" Value="{uc:Enum Working, Type=order:OrderStatus}"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Background" Value="{x:Static Member=working_order_background_brush, MemberType={uc:Nested uc:BTSColors.Orders}}"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
</Style>
<DataTemplate x:Key="{x:Static sp:MiniOrderBookView.RowTemplateKey}">
<sp:MiniOrderBookRowView/>
</DataTemplate>
</ResourceDictionary>
</UserControl.Resources>
<AdornerDecorator>
<Border BorderThickness="4" BorderBrush="LightGray">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<c:DIYGrid
x:Name="_grid"
Grid.Row="0"
Columns="{Binding columns}"
CurrentRow="{Binding current_row, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Rows="{Binding rows}"
RowStyle="{StaticResource {x:Static sp:MiniOrderBookView.RowStyleKey}}"
RowTemplate="{StaticResource {x:Static sp:MiniOrderBookView.RowTemplateKey}}"
SelectionHighlight="{Binding grid_settings_manager.selection_highlight, Mode=OneWay}"
RowsHorizontalScrollBarVisibility="Collapsed"
RowHeight="20"
>
<c:DIYGrid.Resources>
<ResourceDictionary>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Checked.Fill" Color="#FF595959"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Checked.Stroke" Color="#FF262626"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Stroke" Color="#FF27C7F7"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Fill" Color="#FFCCEEFB"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Checked.Stroke" Color="#FF1CC4F7"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Checked.Fill" Color="#FF82DFFB"/>
<PathGeometry x:Key="TreeArrow" Figures="M0,0 L0,6 L6,0 z"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Fill" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Stroke" Color="#FF818181"/>
<Style x:Key="{x:Static sp:OrderBookView.ExpandCollapseToggleStyleKey}" TargetType="{x:Type ToggleButton}">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Width" Value="16"/>
<Setter Property="Height" Value="16"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Background="Transparent" Height="16" Padding="0,5,5,5" Width="16">
<Path x:Name="ExpandPath" Data="{StaticResource TreeArrow}" Fill="{StaticResource TreeViewItem.TreeArrow.Static.Fill}" Stroke="{StaticResource TreeViewItem.TreeArrow.Static.Stroke}">
<Path.RenderTransform>
<RotateTransform Angle="135" CenterY="3" CenterX="3"/>
</Path.RenderTransform>
</Path>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="RenderTransform" TargetName="ExpandPath">
<Setter.Value>
<RotateTransform Angle="180" CenterY="3" CenterX="3"/>
</Setter.Value>
</Setter>
<Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.Static.Checked.Fill}"/>
<Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.Static.Checked.Stroke}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Stroke}"/>
<Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Fill}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsChecked" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Checked.Stroke}"/>
<Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Checked.Fill}"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type ToolTip}">
<Style.Triggers>
<Trigger Property="Content" Value="{x:Static sys:String.Empty}">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
<Trigger Property="Content" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</c:DIYGrid.Resources>
<c:DIYGrid.InputBindings>
<!--<MouseBinding MouseAction="LeftDoubleClick" Command="{x:Static c:DIYGrid.DefaultRowCommand}"/>
<KeyBinding Key="Return" Command="{x:Static c:DIYGrid.DefaultRowCommand}"/> -->
</c:DIYGrid.InputBindings>
<c:DIYGrid.CommandBindings>
<CommandBinding
Command="{x:Static c:DIYGrid.DefaultRowCommand}"
Executed="{x:Static c:DIYGrid.DefaultRowActionExecuted}"
CanExecute="{x:Static c:DIYGrid.DefaultRowActionCanExecute}"
/>
</c:DIYGrid.CommandBindings>
</c:DIYGrid>
</Grid>
</Border>
</AdornerDecorator>
</UserControl>
@@ -0,0 +1,26 @@
using mbts.ui.controls;
using System.Windows.Controls;
namespace mbts.spark {
internal partial class MiniOrderBookView : UserControl {
// IMPORTANT: these enums are stored as strings in the general-purpose GridColumnSettings proto, and are used to ID THE COLUMNS!
// Do NOT RENAME them! However, if you must, be sure to write an IShellWindowMigrationRule or something to account for backwards compatability.
public enum Columns { Security, Symbol, Time, LastChange, User, Account, Exchange, TimeInForce, OrderType, SubType, Side, Size, Price, Filled, AvgFilled, LastPrice, Status, LastMessage, SecurityKey, OrderKey, ParentKey, Cancel, EditableQty, EditablePrice }
public const string
SubTypeFilterTemplateKey = "SubTypeFilterTemplate",
ExpandCollapseToggleStyleKey = "ExpandCollapseToggleStyle",
RowStyleKey = "RowStyle",
RowTemplateKey = "RowTemplateKey",
CVRowStyleKey = "CVRowStyle",
CVRowTemplateKey = "CVRowTemplateKey";
public MiniOrderBookView(OrderBookVM vm) {
InitializeComponent();
DataContext = vm;
}
}
class MiniOrderBookRowView : DIYGrid.HighPerformanceRow<OrderBookRowVM, OrderBookView.Columns> {
public MiniOrderBookRowView() : base() { }
}
}
@@ -194,6 +194,10 @@ namespace mbts.spark {
// quantity
Add(qty_column = new SizeColumn(
new UIntMinMax<OrderRecordTuple>(ort => ort.order.quantity(), nameof(OrderBookRowVM.quantity))));
// edit quantity column
// not usually part of the main order book, but it's useful to add it
// rather than debugging the popup window
//Add(edit_qty_column = new EditableQtyColumn());
// filled quantity
Add(filled_qty_column = new FilledColumn(
new UIntMinMax<OrderRecordTuple>(ort => ort.order.filled(), nameof(OrderBookRowVM.filled_quantity))));
@@ -209,6 +213,10 @@ namespace mbts.spark {
nameof(OrderBookRowVM.price)),
DataGridFilterKnownTemplates.DoubleMinMax,
_wrap_comparer(r => r.price)));
// edit price column
// not usually part of the main order book, but it's useful to add it
// rather than debugging the popup window
//Add(edit_price_column = new OrderBookVM.EditablePriceColumn());
// avg filled price
Add(avg_price_column = new SimpleTextColumn<DoubleMinMaxState>(
Columns.AvgFilled,
@@ -291,6 +299,7 @@ namespace mbts.spark {
public event Action filter_changed;
public CancelColumn cancel_column { get; }
public SecurityColumn security_column { get; }
public SimpleTextColumn<string[]> symbol_column { get; }
public SimpleTextColumn<TimeFilterTuple> time_created_column { get; }
@@ -303,7 +312,9 @@ namespace mbts.spark {
public SimpleTextColumn<OrderSubType[]> sub_type_column { get; }
public SideColumn side_column { get; }
public SizeColumn qty_column { get; }
public EditableQtyColumn edit_qty_column { get; }
public SimpleTextColumn<DoubleMinMaxState> price_column { get; }
public EditablePriceColumn edit_price_column { get; }
public FilledColumn filled_qty_column { get; }
public SimpleTextColumn<DoubleMinMaxState> last_price_column { get; }
public SimpleTextColumn<DoubleMinMaxState> avg_price_column { get; }
@@ -509,7 +520,7 @@ namespace mbts.spark {
: base(key, header, get_text, sort_prop, width, filter, filter_template, comparer) { }
public void draw(OrderBookRowVM row, DrawingContext dc, ColumnGeometry position, double row_height) =>
CellRender.draw_text(dc, _get_glyph_context(row), font_size, _get_text(row), position, RowHeight,
CellRender.draw_text(dc, _get_glyph_context(row), font_size, _get_text(row), position, row_height,
font_brush, null, horizontal_alignment, VerticalAlignment.Center, DefaultCellPadding);
}
@@ -519,7 +530,7 @@ namespace mbts.spark {
: base(Columns.Side, "B/S", r => r.side.ToString(), nameof(OrderBookRowVM.side), DefaultColumnWidths.Side, filter, DataGridFilterKnownTemplates.EnumValues, _wrap_comparer(r => r.side)) { }
public void draw(OrderBookRowVM row, DrawingContext dc, ColumnGeometry position, double row_height) =>
CellRender.draw_text(dc, _get_glyph_context(row), font_size, row.side.ToString(), position, RowHeight,
CellRender.draw_text(dc, _get_glyph_context(row), font_size, row.side.ToString(), position, row_height,
RenderUtils.get_side_brush(row), null, horizontal_alignment, VerticalAlignment.Center, DefaultCellPadding);
}
@@ -530,7 +541,7 @@ namespace mbts.spark {
}
public void draw(OrderBookRowVM row, DrawingContext dc, ColumnGeometry position, double row_height) =>
CellRender.draw_text(dc, _get_glyph_context(row), font_size, row.quantity.ToString(), position, RowHeight,
CellRender.draw_text(dc, _get_glyph_context(row), font_size, row.quantity.ToString(), position, row_height,
RenderUtils.get_side_brush(row), null, horizontal_alignment, VerticalAlignment.Center, DefaultCellPadding);
}
@@ -541,7 +552,7 @@ namespace mbts.spark {
}
public void draw(OrderBookRowVM row, DrawingContext dc, ColumnGeometry position, double row_height) =>
CellRender.draw_text(dc, _get_glyph_context(row), font_size, row.filled_quantity.ToString(), position, RowHeight,
CellRender.draw_text(dc, _get_glyph_context(row), font_size, row.filled_quantity.ToString(), position, row_height,
RenderUtils.get_side_brush(row), null, horizontal_alignment, VerticalAlignment.Center, DefaultCellPadding);
}
@@ -640,6 +651,8 @@ namespace mbts.spark {
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
grid.Children.Add(toggle_button);
grid.Children.Add(security_view);
grid.HorizontalAlignment = HorizontalAlignment.Center;
grid.VerticalAlignment = VerticalAlignment.Center;
//
var border = new Border { Child = grid };
CellRender.set_background_animation_bindings(border, nameof(OrderBookRowVM.security));
@@ -651,6 +664,88 @@ namespace mbts.spark {
base.OnSortDirectionChanged(new_value);
}
}
public class CancelColumn : FrameworkElementColumnBase<Columns> {
readonly BindingBase _command_binding;
public CancelColumn(string command_property) : base(Columns.Cancel) {
id = key.ToString();
Header = DefaultColumnHeaders.Cancel;
_command_binding = new Binding(command_property);
}
public override FrameworkElement view_factory() {
var grid = new Grid() {
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
};
var l1 = new System.Windows.Shapes.Line() {
StrokeThickness = 1,
Stroke = Brushes.White,
X1 = 0.5,
Y1 = 0.5,
X2 = 7,
Y2 = 7
};
var l2 = new System.Windows.Shapes.Line() {
StrokeThickness = 1,
Stroke = Brushes.White,
X1 = 0.5,
Y1 = 7,
X2 = 7,
Y2 = 0.5
};
grid.Children.Add(l1);
grid.Children.Add(l2);
var button = new Button() {
Content = grid,
Background = Brushes.Red,
Foreground = Brushes.White,
Margin = new Thickness(2),
VerticalAlignment = VerticalAlignment.Center,
Height = 14,
Width = 14
};
button.SetBinding(Button.CommandProperty, _command_binding);
return button;
}
}
public class EditableQtyColumn:FrameworkElementColumnBase<Columns> {
public EditableQtyColumn() : base(Columns.EditableQty) {
id = key.ToString();
Header = "Qty";
Width = 64;
}
public override FrameworkElement view_factory() {
var tick_up_down = new TickUpDownNullableUIntCommit();
tick_up_down.SetBinding(TickUpDownNullableUIntCommit.SourceValueProperty, nameof(OrderBookRowVM.prospective_quantity));
tick_up_down.SetBinding(TickUpDownNullableUIntCommit.OnCommitProperty, nameof(OrderBookRowVM.modify_order_quantity));
return tick_up_down;
}
}
public class EditablePriceColumn : FrameworkElementColumnBase<Columns> {
public EditablePriceColumn() : base(Columns.EditablePrice) {
id = key.ToString();
Header = "Price";
Width = 96;
}
public override FrameworkElement view_factory() {
var price_up_down = new PriceEntryCommitControl();
price_up_down.SetBinding(PriceEntryCommitControl.SourceValueProperty, nameof(OrderBookRowVM.prospective_price));
price_up_down.SetBinding(PriceEntryCommitControl.SourceContractSpecProperty, nameof(OrderBookRowVM.contract_spec));
price_up_down.SetBinding(PriceEntryCommitControl.OnCommitProperty, nameof(OrderBookRowVM.modify_order_price));
return price_up_down;
}
}
#endregion
static class RenderUtils {
@@ -14,6 +14,8 @@ namespace mbts.spark {
class OrderBookRowCollection : ObservableCollection<OrderBookRowVM> {
static readonly IEqualityComparer<INode<OrderBookRowVM>> _node_equality_comparer = EqualityComparer.Create<INode<OrderBookRowVM>, uint>(n => n.value.order_key);
readonly Func<OrderRecordTuple, OrderBookRowVM> _row_factory;
/// Critical: Any and all row mutations <see cref="OrderBookRowVM"/> must be executed through <see cref="SortedTree{T, TKey}.TryReplace(TKey, Func{T, T})"/>.
/// Mutations can change the sort-position of a row, and <see cref="_tree"/> will be broken if its elements aren't properly sorted (it relies heavily on binary-search logic).
SortedTree<OrderBookRowVM, uint> _tree;
IComparer<OrderBookRowVM> _comparer;
Func<OrderRecordTuple, bool> _filter;
@@ -6,6 +6,9 @@ using mbts.ui;
using mbts.ui.controls;
using mbts.ui.shell;
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace mbts.spark {
@@ -13,15 +16,34 @@ namespace mbts.spark {
const string _unknown_security_price_format_string = "0.#########";
const int _unknown_security_price_num_fractional_digits = 9;
readonly OrderBookVM _owner;
IRaiseCanExecuteChangedCommand _show_order_modify_cmd, _toggle_expanded_cmd;
bool _is_parent, _is_expanded;
IRaiseCanExecuteChangedCommand _show_order_modify_cmd, _toggle_expanded_cmd, _cancel_cmd, _modify_order_quantity, _modify_order_price;
bool _is_parent, _is_expanded, _is_selected;
int _depth_level;
SecurityMD? _security_md => order_tuple.security_md;
public OrderBookRowVM(OrderBookVM owner, OrderRecordTuple order_tuple) {
// for mini-ob
uint _prospective_quantity;
double _prospective_price;
public OrderBookRowVM(OrderBookVM owner, OrderRecordTuple order_tuple, bool is_expanded) {
_owner = owner;
this.order_tuple = order_tuple;
is_visible = !is_child;
_is_expanded = is_expanded;
prospective_quantity = this.quantity;
prospective_price = this.price;
this.invalidated += OrderBookRowVM_invalidated;
}
private void OrderBookRowVM_invalidated() {
modify_order_quantity?.TryRaiseCanExecuteChanged();
modify_order_price?.TryRaiseCanExecuteChanged();
}
protected override void Dispose(bool disposing) {
this.invalidated -= OrderBookRowVM_invalidated;
base.Dispose(disposing);
}
public event Action invalidated;
@@ -34,6 +56,7 @@ namespace mbts.spark {
public uint parent_order_key => order.ParentKey;
public uint security_key => order.security_key();
public SecurityImmutable? security => _security_md.security();
public ContractSpecificationImmutable? contract_spec => security.spec_or_default();
public string security_text => security.display_name();
public Venue exchange => _security_md.exchange();
public string symbol => _security_md.symbol();
@@ -72,6 +95,29 @@ namespace mbts.spark {
}
}
public int depth_level { get => _depth_level; set => Set(ref _depth_level, value); }
public bool is_selected {
get => _is_selected;
set => Set(ref _is_selected, value);
}
public uint prospective_quantity {
get => _prospective_quantity;
set {
if (Set(ref _prospective_quantity, value)) {
RaisePropertyChanged(nameof(is_qty_dirty));
}
}
}
public double prospective_price {
get => _prospective_price;
set {
if (Set(ref _prospective_price, value)) {
RaisePropertyChanged(nameof(is_price_dirty));
}
}
}
public bool is_qty_dirty => this.prospective_quantity != this.quantity;
public bool is_price_dirty => this.prospective_price != this.price;
// Commands
public ICommand toggle_command => _toggle_expanded_cmd ?? (
_toggle_expanded_cmd = new DelegateCommand(() => is_expanded = !is_expanded));
@@ -79,6 +125,38 @@ namespace mbts.spark {
ICommand DIYGrid.IActionableRowVM.default_command => _show_order_modify_cmd ??
(_show_order_modify_cmd = new DelegateCommand(() => _owner.show_order_modify(this), () => status == OrderStatus.Working));
public ICommand cancel_command => _cancel_cmd ??
(_cancel_cmd = new DelegateCommand(() => _owner.cancel_order(this), () => status == OrderStatus.Working));
public ICommand modify_order_quantity => _modify_order_quantity ??
(_modify_order_quantity = new DelegateCommand(
(desired_quantity) => {
_owner.modify_order_quantity(this, (uint)desired_quantity);
_unselect_me();
},
(desired_quantity) =>
(desired_quantity != null && this.status == OrderStatus.Working && (uint)desired_quantity != this.quantity)
|| is_qty_dirty
)
);
public ICommand modify_order_price => _modify_order_price ??
(_modify_order_price = new DelegateCommand(
(desired_price) => {
_owner.modify_order_price(this, (double)desired_price);
_unselect_me();
},
(desired_price) =>
(desired_price != null && this.status == OrderStatus.Working && (double)desired_price != this.price)
|| is_price_dirty
)
);
private void _unselect_me() {
this.is_selected = false;
_owner.current_row = null;
}
// These fns present a way for the orderbook to avoid noisy, intermittent collection changes during "Expand/Collapse All" ops,
// when incremental changes are ignored in favor of a full reset, after 'is_expanded' is updated for all rows.
internal void expand_internal() => Set(ref _is_expanded, true);
@@ -103,6 +181,14 @@ namespace mbts.spark {
// however, the order-type and security cells DO use databindings - if these cells have changed, the PropertyChanged event must be raised regardless of whether or not invalidated is raised
if (old_order.order_type() != order.order_type())
RaisePropertyChanged(nameof(order_type), nameof(order_metadata));
if (old_order.quantity() != order.quantity()) {
RaisePropertyChanged(nameof(quantity));
RaisePropertyChanged(nameof(is_qty_dirty));
}
if (old_order.price() != order.price()) {
RaisePropertyChanged(nameof(price));
RaisePropertyChanged(nameof(is_price_dirty));
}
if (!had_security && _security_md.HasValue) {
RaisePropertyChanged(nameof(security), nameof(security_text));
// need to raise invalidated to refresh the price cells (the security.ContractSpec determines how they are formatted - Ticks!)
@@ -16,6 +16,7 @@ using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;
using static bts.shell.OrderBookWindowFactory;
@@ -33,44 +34,84 @@ namespace mbts.spark {
readonly IWindowSettingsManager<OrderBookGridSettings> _settings_manager;
readonly List<IDisposable> _resources;
OrderBookStartupData _state;
bool _is_row_collection_populated;
public OrderBookVM(IObservable<string> owner_title, IBus bus, INotificationService notification_service, OrdersModel model, IWindowSettingsManager<OrderBookGridSettings> settings_manager) {
public OrderBookVM(IObservable<string> owner_title, IBus bus, INotificationService notification_service, OrdersModel model, IWindowSettingsManager<OrderBookGridSettings> settings_manager, bool rows_are_initially_expanded = false) {
_bus = bus;
_model = model;
_settings_manager = settings_manager;
_columns = new OrderBookColumnCollection(bus, model, model.on_order_securities.Select(u => (u.added.Values.Select(smd => smd.security), u.removed.Values.Select(smd => smd.security))));
_row_collection = new OrderBookRowCollection(ort => new OrderBookRowVM(this, ort), _columns.get_sorting_data().comparer) { filter = _columns.get_filter() };
// we use an ObservableAppendCollection b/c the mini-ob needs a cancel column at the front
columns = new ObservableAppendCollection<DIYGrid.ColumnBase>(_columns);
_row_collection = new OrderBookRowCollection(ort => new OrderBookRowVM(this, ort, rows_are_initially_expanded), _columns.get_sorting_data().comparer) { filter = _columns.get_filter() };
_row_collection.CollectionChanged += _row_collection_CollectionChanged;
_current_row = backing<OrderBookRowVM>(nameof(current_row));
_columns.filter_changed += on_filter_changed;
collapse_all_rows_command = new DelegateCommand(_row_collection.collapse_all);
expand_all_rows_command = new DelegateCommand(_row_collection.expand_all);
grid_settings_manager = _create_grid_settings_manager(owner_title, bus, notification_service, model, rows, columns);
grid_settings_manager = _create_grid_settings_manager(owner_title, bus, notification_service, model, rows, core_columns);
_resources = new List<IDisposable> {
model.on_order_tuples_table.OnDispatcher().Subscribe(_row_collection.update),
settings_manager.subscribe_current().OnDispatcher().Subscribe(grid_settings_manager),
grid_settings_manager,
Disposable.Create(() => {
_columns.filter_changed -= on_filter_changed;
_row_collection.CollectionChanged -= _row_collection_CollectionChanged;
Disposable.dispose(_row_collection);
}),
_columns
};
if (settings_manager != null) {
_resources.Add(settings_manager.subscribe_current().OnDispatcher().Subscribe(grid_settings_manager));
}
void on_filter_changed() => _row_collection.filter = _columns.get_filter();
}
private void _row_collection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
is_row_collection_populated = _row_collection.Count != 0;
}
public event Action<OrderRecordImmutable?> selected_order_changed;
public event Action<bool> OnDisposed;
public ObservableCollection<DIYGrid.ColumnBase> columns => _columns;
public ObservableAppendCollection<DIYGrid.ColumnBase> columns { get; }
public ObservableCollection<DIYGrid.ColumnBase> core_columns => _columns;
public ObservableCollection<OrderBookRowVM> rows => _row_collection;
public OrderBookRowVM current_row { get => _current_row.Value; set => _current_row.Value = value ?? _selected_rows.FirstOrDefault(); }
public OrderBookRowVM current_row {
get => _current_row.Value;
set {
_current_row.Value = value;
// this is so that when the current_row is set to null from
// the row_vm, we propagate the change up to the OrderBookWindow
// so that the cancel and modify commands can_execute is updated.
// Note that this is really only for if/when the edit_xxx columns
// from the mini-ob are present in regular orderbook, else this is
// a no-op.
selected_order_changed?.Invoke(current_order);
}
}
public OrderRecordImmutable? current_order => current_row?.order;
public IEnumerable<OrderRecordImmutable> selected_orders => _selected_rows.Select(r => r.order);
public _GridSettingsManager grid_settings_manager { get; }
public ICommand collapse_all_rows_command { get; }
public ICommand expand_all_rows_command { get; }
public bool is_row_collection_populated {
get => _is_row_collection_populated;
set => Set(ref _is_row_collection_populated, value);
}
public void row_selection_changed(SelectionChangedEventArgs e) {
if (e.RemovedItems != null) {
foreach (var row_vm in e.RemovedItems.Cast<OrderBookRowVM>()) {
row_vm.is_selected = false;
}
}
if (e.AddedItems != null) {
foreach (var row_vm in e.AddedItems.Cast<OrderBookRowVM>()) {
row_vm.is_selected = true;
}
}
RowSelectionHelper.apply_changes(_selected_rows, e);
selected_order_changed?.Invoke(current_order);
}
@@ -131,6 +172,15 @@ namespace mbts.spark {
internal void show_order_modify(OrderBookRowVM row) =>
_bus.post(SparkTags.ShowModifyOrderTag, row.order_key);
internal void cancel_order(OrderBookRowVM row) =>
_bus.post(SparkTags.CancelOrders, new List<uint> { row.order_key });
internal void modify_order_quantity(OrderBookRowVM row, uint size) =>
_bus.post(SparkTags.UpdateOrder, (row.order_key, row.price, size));
internal void modify_order_price(OrderBookRowVM row, double price) =>
_bus.post(SparkTags.UpdateOrder, (row.order_key, price, row.quantity));
internal void on_expanded_changed(OrderBookRowVM row) {
using (_row_collection.defer_refresh(true)) {
if (row.is_expanded) {
@@ -187,7 +237,8 @@ namespace mbts.spark {
return pvm;
},
(gen, anims) => new OrderBookGridSettings(gen, anims.Select(a => new OrderRecordTuplePredicateAnimations(a.predicate_builder, a.cell_animations, a.row_animations, a.sound_notifications))),
notification_service.data_cache, col_settings_flags);
(notification_service == null) ? null : notification_service.data_cache,
col_settings_flags);
}
static OrderRecordTuplePredicate.PredicateTypeOneofCase _corresponding_predicate_type(Columns col) {
@@ -5,7 +5,7 @@ namespace mbts.spark {
internal partial class OrderBookView : UserControl {
// IMPORTANT: these enums are stored as strings in the general-purpose GridColumnSettings proto, and are used to ID THE COLUMNS!
// Do NOT RENAME them! However, if you must, be sure to write an IShellWindowMigrationRule or something to account for backwards compatability.
public enum Columns { Security, Symbol, Time, LastChange, User, Account, Exchange, TimeInForce, OrderType, SubType, Side, Size, Price, Filled, AvgFilled, LastPrice, Status, LastMessage, SecurityKey, OrderKey, ParentKey }
public enum Columns { Security, Symbol, Time, LastChange, User, Account, Exchange, TimeInForce, OrderType, SubType, Side, Size, Price, Filled, AvgFilled, LastPrice, Status, LastMessage, SecurityKey, OrderKey, ParentKey, Cancel, EditableQty, EditablePrice }
public const string
SubTypeFilterTemplateKey = "SubTypeFilterTemplate",
ExpandCollapseToggleStyleKey = "ExpandCollapseToggleStyle",
@@ -14,8 +14,6 @@ namespace mbts.spark {
CVRowStyleKey = "CVRowStyle",
CVRowTemplateKey = "CVRowTemplateKey";
public const double RowHeight = 17;
public OrderBookView(OrderBookVM vm) {
InitializeComponent();
DataContext = vm;
@@ -23,6 +21,6 @@ namespace mbts.spark {
}
class OrderBookRowView : DIYGrid.HighPerformanceRow<OrderBookRowVM, OrderBookView.Columns> {
public OrderBookRowView() : base(OrderBookView.RowHeight) { }
public OrderBookRowView() : base() { }
}
}
@@ -131,7 +131,7 @@ namespace mbts.spark {
return _vm.grid_settings_manager.create_vm(
// we need to get the most up to date GridSettings when launching b/c users may
// have changed some settings on the grid directly, like column widths.
s.general.with(_vm.columns.Select(c => c.create())),
s.general.with(_vm.core_columns.Select(c => c.create())),
this.observe_title()
);
}
@@ -167,11 +167,9 @@ namespace mbts.spark {
}
private void _vm_selected_order_changed(OrderRecordImmutable? e) {
if (e.HasValue) {
_modify_order_command.raiseCanExecuteChanged();
_cancel_selected_orders_command.raiseCanExecuteChanged();
_recreate_selected_orders_command.raiseCanExecuteChanged();
}
}
}
}
@@ -90,6 +90,8 @@ namespace bts.shell {
public static OrderBookGridSettings DefaultGrid => new OrderBookGridSettings(_default_general_grid);
static GridSettings _default_general_grid => GridSettings.Default.with(DefaultColumns.all, DefaultColumns.sorting_criterion);
public static GridSettings default_mini_grid => GridSettings.Default.with(DefaultColumns.mini, DefaultColumns.sorting_criterion);
static class DefaultColumns {
public static GridColumnSettings security => new GridColumnSettings(Columns.Security.ToString(), DIYGrid.DefaultColumnHeaders.Security, width: DIYGrid.DefaultColumnWidths.Security);
@@ -110,7 +112,7 @@ namespace bts.shell {
public static GridColumnSettings last_price => new GridColumnSettings(Columns.LastPrice.ToString(), "Last Filled", width: DIYGrid.DefaultColumnWidths.LastPrice, horizontal_alignment: HorizontalAlignment.Right);
public static GridColumnSettings status => new GridColumnSettings(Columns.Status.ToString(), "Status", width: 80);
public static GridColumnSettings last_message => new GridColumnSettings(Columns.LastMessage.ToString(), "Last Message", width: DIYGrid.DefaultColumnWidths.LastMessage);
public static GridColumnSettings security_key => new GridColumnSettings(Columns.SecurityKey.ToString(), DIYGrid.DefaultColumnHeaders.SecurityKey, width: DIYGrid.DefaultColumnWidths.SecurityKey);
public static GridColumnSettings security_key => new GridColumnSettings(Columns.SecurityKey.ToString(), DIYGrid.DefaultColumnHeaders.SecurityKey, is_visible: false, width: DIYGrid.DefaultColumnWidths.SecurityKey);
public static GridColumnSettings order_key => new GridColumnSettings(Columns.OrderKey.ToString(), DIYGrid.DefaultColumnHeaders.OrderKey, width: DIYGrid.DefaultColumnWidths.OrderKey);
public static GridColumnSettings parent_key => new GridColumnSettings(Columns.ParentKey.ToString(), "Parent Key", width: DIYGrid.DefaultColumnWidths.ParentKey);
@@ -145,7 +147,23 @@ namespace bts.shell {
yield return parent_key;
}
}
}
private static HashSet<GridColumnSettings> _mini_mode_columns_to_hide = new HashSet<GridColumnSettings> {
time_created, exchange, sub_type, quantity, price, avg_price, last_price, status, last_message, security_key, order_key, parent_key
};
public static IEnumerable<GridColumnSettings> mini {
get {
foreach (var col_setting in all) {
if (_mini_mode_columns_to_hide.Contains(col_setting)) {
yield return col_setting.with(is_visible: false);
} else {
yield return col_setting;
}
}
}
}
}
}
[ProtoContract]
@@ -25,6 +25,8 @@ namespace mbts.ui.spark {
public DataTemplate JoinOrderTemplate { get; set; }
public DataTemplate TopOrderTemplate { get; set; }
public DataTemplate CoverOrderTemplate { get; set; }
public DataTemplate OCOOrderTemplate { get; set; }
public DataTemplate PricerOrderTemplate { get; set; }
public DataTemplate OffsetOrderTemplate { get; set; }
public DataTemplate TriggerOrderTemplate { get; set; }
public DataTemplate IcebergOrderTemplate { get; set; }
@@ -43,6 +45,8 @@ namespace mbts.ui.spark {
case CustomOrderDefinition.CustomOneofCase.Join: return JoinOrderTemplate;
case CustomOrderDefinition.CustomOneofCase.Top: return TopOrderTemplate;
case CustomOrderDefinition.CustomOneofCase.Cover: return CoverOrderTemplate;
case CustomOrderDefinition.CustomOneofCase.Oco : return OCOOrderTemplate;
case CustomOrderDefinition.CustomOneofCase.Pricer: return PricerOrderTemplate;
case CustomOrderDefinition.CustomOneofCase.Offset: return OffsetOrderTemplate;
case CustomOrderDefinition.CustomOneofCase.Trigger: return TriggerOrderTemplate;
case CustomOrderDefinition.CustomOneofCase.Iceberg: return IcebergOrderTemplate;
@@ -139,13 +139,13 @@ namespace mbts.spark {
tif => time_in_forces.Contains(tif));
_dispose = Disposable.Create(() => _order_type.Changed -= on_selected_order_type_changed);
// local methods
IOrderTypeVM create_order_type_vm(CustomOrderDefinitionImmutable cd, string id, string display_name) {
IOrderTypeVM create_order_type_vm(CustomOrderDefinitionImmutable? cd, string id, string display_name) {
IOrderTypeVM vm = null;
if(cd.CustomCase == CustomOrderDefinition.CustomOneofCase.Dynamic)
vm = OrderTypeVMFactory.create(cd.CustomCase, id, display_name, model, security_md_source, cd.Dynamic.DynamicOrderType);
if(cd?.CustomCase == CustomOrderDefinition.CustomOneofCase.Dynamic)
vm = OrderTypeVMFactory.create(cd.Value.CustomCase, id, display_name, model, security_md_source, cd.Value.Dynamic.DynamicOrderType);
else
vm = OrderTypeVMFactory.create(cd.CustomCase, id, display_name, model, security_md_source);
vm.load_from(cd);
vm = OrderTypeVMFactory.create(cd.Value.CustomCase, id, display_name, model, security_md_source);
vm.load_from(cd.Value);
return vm;
}
InlineUserProperty<IOrderTypeVM> get_order_type_vm_prop(InlineOrderProperties p) {
@@ -126,6 +126,8 @@ namespace mbts.spark
return _child_order_choices;
}
}
public bool has_child => _order_def_tags.Any();
public IOrderTypeVM child_order
{
@@ -0,0 +1,257 @@
using bts.api;
using bts.api.orderman;
using mbts.ui;
using mbts.ui.utility;
using mbts.utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using static bts.api.orderman.CustomOrderDefinition;
namespace mbts.spark
{
static partial class OrderTypeVMFactory
{
class InlineOCOOrderProperties
{
public InlineOCOOrderProperties(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<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
var othertype = CustomOneofCase.Limit;
this.selected_other_order_type = new InlineUserProperty<OrderTemplateHeader>(new OrderTemplateHeader(othertype), true);
this.other_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
other_ticks = new InlineUserProperty<int>(1, false);
other_side = new InlineUserProperty<bts.api.RelativeSide>(bts.api.RelativeSide.Same, false);
}
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<OrderTemplateHeader> selected_other_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> other_order_types;
public readonly InlineUserProperty<int> other_ticks;
public readonly InlineUserProperty<bts.api.RelativeSide> other_side;
}
class OCOOrderVM : OrderTypeVMBase<OCOOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable
{
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
InlineOCOOrderProperties _inline_props;
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _other_order_choices;
IOrderTypeVM _other_order;
IDisposable _other_order_errors_sub;
public int other_ticks { get; set; } = 1;
public bts.api.RelativeSide other_side { get; set; } = bts.api.RelativeSide.Same;
public OCOOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineOCOOrderProperties(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 OCOOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineOCOOrderProperties> 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()
.Subscribe(smd => _security = smd.security),
inline_properties.OnDispatcher()
.Subscribe(p =>
{
if (_order_types.Count == 0 || p.child_order_types.force_override)
{
_order_types.SetItems(p.child_order_types.value);
}
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override))
{
_select_child_order(p.selected_child_order_type.value.key.type);
}
if (_other_order_choices != null && (_other_order == null || p.selected_other_order_type.force_override))
{
_select_other_order(p.selected_other_order_type.value.key.type);
}
if (p.other_ticks.force_override)
{
other_ticks = p.other_ticks.value;
RaisePropertyChanged(nameof(other_ticks));
}
if (p.other_side.force_override)
{
other_side = p.other_side.value;
RaisePropertyChanged(nameof(other_side));
}
_inline_props = p;
_validate();
})
);
_validate();
}
public override void assign_to(CustomOrderDefinition value)
{
if (_child_order == null)
_select_child_order(model.factory.default_order_type(_security.Value, true));
if (_other_order == null )
_select_other_order(model.factory.default_order_type(_security.Value, true));
_validate();
if (!HasErrors)
{
var i = factory.oco_order();
i.OtherTicks = other_ticks;
i.OtherSide = other_side;
child_order.assign_to(i.Child);
if (other_order != null)
other_order.assign_to(i.Other);
value.Oco = i;
}
}
public IEnumerable<bts.api.RelativeSide> other_side_types => EnumHelper.get_values_except<bts.api.RelativeSide>(bts.api.RelativeSide.Undefined);
public ICollection<IOrderTypeVM> child_order_types
{
get
{
if (_child_order_choices == null)
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
return _child_order_choices;
}
}
public ICollection<IOrderTypeVM> other_order_types
{
get
{
if (_other_order_choices == null)
_other_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
return _other_order_choices;
}
}
public IOrderTypeVM child_order
{
get
{
init();
return _child_order;
}
set
{
Disposable.dispose(ref _child_order_errors_sub);
_child_order = value;
_child_order?.init();
if (_child_order is INotifyDataErrorInfo ndei)
{
ndei.ErrorsChanged += on_errors_changed;
void on_errors_changed(object s, DataErrorsChangedEventArgs e) =>
_validate();
_child_order_errors_sub = Disposable.Create(() => ndei.ErrorsChanged -= on_errors_changed);
}
_validate();
RaisePropertyChanged(nameof(child_order));
}
}
public IOrderTypeVM other_order
{
get
{
init();
return _other_order;
}
set
{
Disposable.dispose(ref _other_order_errors_sub);
_other_order = value;
_other_order?.init();
if (_other_order is INotifyDataErrorInfo ndei)
{
ndei.ErrorsChanged += on_errors_changed;
void on_errors_changed(object s, DataErrorsChangedEventArgs e) =>
_validate();
_other_order_errors_sub = Disposable.Create(() => ndei.ErrorsChanged -= on_errors_changed);
}
_validate();
RaisePropertyChanged(nameof(other_order));
}
}
public void Dispose()
{
Disposable.dispose(ref _dispose);
if (_child_order_choices != null)
_child_order_choices.OfType<IDisposable>().DisposeAll();
if (_other_order_choices != null)
_other_order_choices.OfType<IDisposable>().DisposeAll();
}
public override void init()
{
if (_child_order == null && _security.HasValue)
_select_child_order();
if (_other_order == null && _security.HasValue)
_select_other_order();
_validate();
}
void _select_child_order()
{
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
_inline_props.selected_child_order_type.value.key.type :
model.factory.default_order_type(_security.Value, true);
_select_child_order(ot);
}
void _select_child_order(CustomOneofCase ot)
{
_child_order = child_order_types.FirstOrDefault(vm => vm.order_type == ot);
if (_child_order == null)
_child_order = child_order_types.FirstOrDefault();
RaisePropertyChanged(nameof(child_order));
}
void _select_other_order()
{
CustomOneofCase ot = _inline_props != null && _inline_props.selected_other_order_type.has_value ?
_inline_props.selected_other_order_type.value.key.type :
model.factory.default_order_type(_security.Value, true);
_select_other_order(ot);
}
void _select_other_order(CustomOneofCase ot)
{
_other_order = other_order_types.FirstOrDefault(vm => vm.order_type == ot);
if (_other_order == null)
_other_order = other_order_types.FirstOrDefault();
RaisePropertyChanged(nameof(other_order));
}
void _validate()
{
if (_child_order == null || (_child_order is INotifyDataErrorInfo ndei && ndei.HasErrors))
set_error(nameof(child_order), string.Empty, true);
else clear_error(nameof(child_order));
if ((_other_order == null ) || (_other_order is INotifyDataErrorInfo hdei && hdei.HasErrors))
set_error(nameof(other_order), string.Empty, true);
else clear_error(nameof(other_order));
}
}
}
}
@@ -15,11 +15,12 @@ namespace mbts.spark {
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 oco(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new OCOOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM pricer(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new PricerOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM offset(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new OffsetOrderVM(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);
@@ -34,11 +35,12 @@ namespace mbts.spark {
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.Oco : return oco(model, security_md_source, id, display_name);
case CustomOneofCase.Pricer: return pricer(model, security_md_source, id, display_name);
case CustomOneofCase.Offset: return offset(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);
@@ -15,52 +15,42 @@ namespace mbts.spark
{
static partial class OrderTypeVMFactory
{
class InlineTickOrderProperties
class InlinePricerOrderProperties
{
public InlineTickOrderProperties (OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
public InlinePricerOrderProperties (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<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);
cross_ticks = new InlineUserProperty<uint>(0, false);
max_chase_ticks = new InlineUserProperty<uint>(10, false);
detach_on_toward = new InlineUserProperty<bool>(true, false);
price_offset_ticks = new InlineUserProperty<int>(0, false);
price_factor = new InlineUserProperty<double>(0, false);
}
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;
public readonly InlineUserProperty<uint> cross_ticks;
public readonly InlineUserProperty<uint> max_chase_ticks;
public readonly InlineUserProperty<bool> detach_on_toward;
public readonly InlineUserProperty<int> price_offset_ticks;
public readonly InlineUserProperty<double> price_factor;
}
class TickOrderVM : OrderTypeVMBase<TickOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable
class PricerOrderVM : OrderTypeVMBase<PricerOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable
{
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
InlineTickOrderProperties _inline_props;
InlinePricerOrderProperties _inline_props;
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
public uint tick_offset_on_deploy { get; set; } = 0;
public bts.spark.QuantityMeasure cross_threshold { get; set; } = new bts.spark.QuantityMeasure() { Ratio = 1.0, Absolute = 1 };
public uint cross_ticks { get; set; } = 0;
public uint max_chase_ticks { get; set; } = 10;
public bool detach_on_toward { get; set; } = true;
public int price_offset_ticks { get; set; } = 0;
public double price_factor { get; set; } = 1.0;
public TickOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
public PricerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineTickOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name) { }
new InlinePricerOrderProperties(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, string id, string display_name) : base(model, id, display_name)
public PricerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlinePricerOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
{
_security_md_source = security_md_source;
_dispose = Disposable.Create(
@@ -76,31 +66,16 @@ namespace mbts.spark
{
_select_child_order(p.selected_child_order_type.value.key.type);
}
if (p.tick_offset_on_deploy.force_override)
if (p.price_offset_ticks.force_override)
{
tick_offset_on_deploy = p.tick_offset_on_deploy.value;
RaisePropertyChanged(nameof(tick_offset_on_deploy));
price_offset_ticks = p.price_offset_ticks.value;
RaisePropertyChanged(nameof(price_offset_ticks));
}
if (p.cross_threshold.force_override)
if (p.price_factor.force_override)
{
cross_threshold = p.cross_threshold.value;
RaisePropertyChanged(nameof(cross_threshold));
}
if (p.cross_ticks.force_override)
{
cross_ticks = p.cross_ticks.value;
RaisePropertyChanged(nameof(cross_ticks));
}
if (p.max_chase_ticks.force_override)
{
max_chase_ticks = p.max_chase_ticks.value;
RaisePropertyChanged(nameof(max_chase_ticks));
}
if (p.detach_on_toward.force_override)
{
detach_on_toward = p.detach_on_toward.value;
RaisePropertyChanged(nameof(detach_on_toward));
}
price_factor = p.price_factor.value;
RaisePropertyChanged(nameof(price_factor));
}
_inline_props = p;
_validate();
})
@@ -115,14 +90,11 @@ namespace mbts.spark
_validate();
if (!HasErrors)
{
var i = factory.tick_order();
i.TickOffsetOnDeploy = tick_offset_on_deploy;
i.CrossThreshold = cross_threshold;
i.CrossTicks = cross_ticks;
i.MaxChaseTicks = max_chase_ticks;
i.DetachOnToward = detach_on_toward;
var i = factory.pricer_order();
i.PriceOffsetTicks = price_offset_ticks;
i.PriceFactor = price_factor;
child_order.assign_to(i.Child);
value.Tick = i;
value.Pricer = i;
}
}
@@ -19,7 +19,8 @@ namespace mbts.spark {
var so = model.factory.spreader_order();
so.Security = s.CloneToMutable();
so.ExecutionStrategy = strategy.CloneToMutable();
return new InlineUserProperty<SpreaderOrderDefinitionImmutable>(so, true);
var soi = new SpreaderOrderDefinitionImmutable(so);
return new InlineUserProperty<SpreaderOrderDefinitionImmutable>(soi, true);
})), id, display_name) { }
public SpreaderOrderVM(
+7 -4
View File
@@ -93,10 +93,13 @@ namespace mbts.spark {
#endregion
#region Input
public async Task<uint?> send_order(OrderDefinitionImmutable order, double price, uint size) {
var result = (await send_order_get_error(order, price, size));
_activity.on_send_order(order, price, size, result.key, result.error);
return result.key;
public async Task<uint?> send_order(OrderDefinitionImmutable? order, double price, uint size) {
if (order.HasValue) {
var result = (await send_order_get_error(order.Value, price, size));
_activity.on_send_order(order.Value, price, size, result.key, result.error);
return result.key;
}
return 0;
}
async Task<(uint? key, string error)> send_order_get_error(OrderDefinitionImmutable order, double price, uint size) {
+11 -1
View File
@@ -31,7 +31,7 @@
<Reference Include="WindowsBase" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.ComponentModel.Composition" />
<PackageReference Include="Google.Protobuf" Version="3.4.0" />
<PackageReference Include="Google.Protobuf" Version="3.6.1" />
<PackageReference Include="IronPython" Version="2.7.7" />
<PackageReference Include="NAudio" Version="1.8.4" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
@@ -54,6 +54,7 @@
<ItemGroup>
<None Remove="Sounds\game_sound_correct.wav" />
<None Remove="Sounds\whistle.wav" />
<None Remove="view\Controls\TickUpDown\TickUpDownNullableUIntCommit.xaml" />
<None Remove="view\Shell\Workspaces\WorkspacesView.xaml" />
</ItemGroup>
<ItemGroup>
@@ -71,11 +72,20 @@
<Folder Include="view\Extensions\ItemsControl\ObservableItemsSource\" />
</ItemGroup>
<ItemGroup>
<Compile Update="view\Controls\TickUpDown\TickUpDownNullableUIntCommit.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="view\Shell\Workspaces\WorkspacesDialogView.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<None Update="Modules\Trading\OrderBook\MiniOrderBook\MiniOrderBookView.xaml">
<Generator>MSBuild:Compile</Generator>
</None>
<None Update="Modules\Trading\OrderBook\MiniOrderBook\OrderBookView.xaml">
<Generator>MSBuild:Compile</Generator>
</None>
<None Update="view\Controls\DIYGrid\Settings\SimpleGridSettingsDialog.xaml">
<Generator>MSBuild:Compile</Generator>
</None>
@@ -211,6 +211,8 @@ namespace mbts.ui {
public static BTSColor lean_order { get { return new BTSColor(255, 170, 210); } }
public static BTSColor join_order { get { return new BTSColor(200, 171, 232); } }
public static BTSColor cover_order { get { return new BTSColor(134, 232, 224); } }
public static BTSColor oco_order { get { return new BTSColor(110, 94, 11); } }
public static BTSColor pricer_order { get { return new BTSColor(170, 132, 150); } }
public static BTSColor trigger_order { get { return new BTSColor(172, 255, 179); } }
public static BTSColor off_order { get { return new BTSColor(0x8a, 0x00, 0x5f); } }//8a005f
public static BTSColor top_order { get { return new BTSColor(0xdd, 0x7a, 0x27); } }//dd7a27
@@ -51,7 +51,7 @@ namespace bts.proto {
static class DateTimeProviderExtensions {
public static DateTime get_date_time(this DateTimeProvider dtp) {
switch (dtp.mode) {
case DateTimeProviderMode.CMEOpen: return MarketSchedule.get_cme_gen_open();
case DateTimeProviderMode.CMEOpen: return MarketSchedule.get_start_of_trading_day();
case DateTimeProviderMode.Today: return DateTime.Today;
case DateTimeProviderMode.Explicit:
default: return dtp.explicit_date.GetValueOrDefault();
+16
View File
@@ -9,6 +9,7 @@ using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;
using FontFamily = System.Windows.Media.FontFamily;
@@ -38,6 +39,7 @@ namespace mbts.ui.controls {
CustomOrderDefinition.CustomOneofCase _parent_algo_type;
(Point p1, Point p2, Point p3) _current_triangle_vertices;
StreamGeometry _triangle_geometry;
Popup _popup;
static Badge() {
@@ -181,6 +183,7 @@ namespace mbts.ui.controls {
_has_multiple_orders_at_level = HasMultipleOrdersAtLevel;
_is_hedge_order = IsHedgeOrder;
_gcr.glyph_context = GlyphContext.create(FontFamily, FontWeight);
_popup = Popup;
}
public static readonly DependencyProperty TextLinesProperty =
@@ -264,6 +267,19 @@ namespace mbts.ui.controls {
(b, v) => b._is_hedge_order = v,
false);
public Popup Popup {
get { return (Popup)GetValue(PopupProperty); }
set { SetValue(PopupProperty, value); }
}
public static readonly DependencyProperty PopupProperty =
WPFHelper.create_dp<Popup, Badge>(
nameof(Popup),
FrameworkPropertyMetadataOptions.AffectsRender,
(b, v) => b._popup = v,
null);
protected override Size ArrangeOverride(Size finalSize) => finalSize;
protected override Size MeasureOverride(Size availableSize) {
@@ -36,7 +36,6 @@ namespace mbts.ui.controls {
Symbol = 78,
Time = 112,
TimeInForce = 47,
TradeKey = 76,
User = 53,
Aggressor = 80,
Volume = 74,
@@ -71,7 +70,6 @@ namespace mbts.ui.controls {
ImpliedSize = "Qty (I)",
Symbol = "Symbol",
TimeInForce = "TIF",
TradeKey = "Trade Key",
User = "User",
Time = "Time",
Aggressor = "Aggressor",
@@ -97,7 +95,8 @@ namespace mbts.ui.controls {
DayPnL = "Day PnL",
TotalNetPos = "Total Net Pos",
TotalPnL = "Total PnL",
PnLPrice = "PnL Price";
PnLPrice = "PnL Price",
Cancel = "Cancel";
}
public interface IKeyedColumn<TColKey> {
@@ -139,6 +139,7 @@ namespace mbts.ui.controls {
public static readonly Thickness
DefaultCellPadding = new Thickness(4, 2, 4, 2),
AnimatableCellPadding = new Thickness(8, 2, 4, 2);
public static readonly Visibility DefaultRowsHorizontalScrollBarVisibility = Visibility.Visible;
#region RoutedCommands
public static readonly RoutedCommand SortCommand = new RoutedCommand(), DefaultRowCommand = new RoutedCommand();
@@ -695,6 +696,14 @@ namespace mbts.ui.controls {
public static readonly DependencyProperty SelectionModeProperty = ListBox.SelectionModeProperty.AddOwner(typeof(DIYGrid));
public Visibility RowsHorizontalScrollBarVisibility {
get { return (Visibility)GetValue(RowsHorizontalScrollBarVisibilityProperty); }
set { SetValue(RowsHorizontalScrollBarVisibilityProperty, value); }
}
public static readonly DependencyProperty RowsHorizontalScrollBarVisibilityProperty = DependencyProperty.Register(
nameof(RowsHorizontalScrollBarVisibility), typeof(Visibility), typeof(DIYGrid), new PropertyMetadata(DefaultRowsHorizontalScrollBarVisibility));
#endregion
// Internal Methods
@@ -62,7 +62,8 @@
<Setter Property="ColumnHeaderStyle">
<Setter.Value>
<Style TargetType="GridViewColumnHeader">
<Setter Property="Background" Value="{mbts:BTSColor header}"/>
<!-- Background - note that we're settings this property on the containing stackpanel in which the GridViewHeaderRowPresenter resides -->
<Setter Property="Background" Value="{x:Null}"/>
<Setter Property="Foreground" Value="{mbts:BTSColor header_text}"/>
<Setter Property="BorderBrush" Value="{mbts:BTSColor header}"/>
<Setter Property="BorderThickness" Value="0,1,1,0"/>
@@ -301,7 +302,9 @@
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
x:Name="_header_scroll_viewer">
<StackPanel>
<!-- setting the bg color for this stackpanel is a work-around for the vertical white lines that appear on high-dpi displays between some columns -->
<!-- in reality, there is some high dpi rounding thing going on, but that's a battle for another day -->
<StackPanel Background="{mbts:BTSColor Name=header}">
<!-- We don't need super headers over the fixed columns -->
<StackPanel Orientation="Horizontal" x:Name="_super_headers" />
<GridViewHeaderRowPresenter x:Name="_header_scroll" AllowsColumnReorder="False" ColumnHeaderContainerStyle="{TemplateBinding ColumnHeaderStyle}" UseLayoutRounding="True" />
@@ -332,7 +335,7 @@
</ControlTemplate>
</bts:DIYGridRowsPresenter.Template>
</bts:DIYGridRowsPresenter>
<ScrollBar Grid.Row="3" Grid.Column="1" Orientation="Horizontal" LargeChange="10" x:Name="_scroll_horiz" />
<ScrollBar Grid.Row="3" Grid.Column="1" Orientation="Horizontal" LargeChange="10" x:Name="_scroll_horiz" Visibility="{TemplateBinding RowsHorizontalScrollBarVisibility}" />
<!-- todo: All edit controls go in a canvas - edit api is called with an edit type. Hide all controls -->
<!-- This stole hours of my life. The Text binding down there used to be 'value' and I was encountering -->
@@ -1,4 +1,5 @@
using bts.proto;
using bts.utils;
using ProtoBuf;
using System;
using System.ComponentModel;
@@ -18,7 +19,7 @@ namespace mbts.ui.settings {
}
[ProtoContract]
class GridColumnSettings {
class GridColumnSettings : IEquatable<GridColumnSettings> {
const bool
_default_is_visible = true,
_default_is_collapsed = false;
@@ -103,5 +104,43 @@ namespace mbts.ui.settings {
width ?? this.width,
horizontal_alignment ?? this.horizontal_alignment,
horizontal_offset ?? this.horizontal_offset);
public bool Equals(GridColumnSettings other) =>
other != null &&
id == other.id &&
display_name == other.display_name &&
is_visible == other.is_visible &&
is_collapsed == other.is_collapsed &&
font_weight_override.Equals(other.font_weight_override) &&
font_color_override.Equals(other.font_color_override) &&
width == other.width &&
horizontal_alignment == other.horizontal_alignment &&
horizontal_offset == other.horizontal_offset &&
display_name == other.display_name;
public override bool Equals(object obj) =>
Equals(obj as GridColumnSettings);
public override int GetHashCode() =>
EqualityComparer.aggregate_hash(
id.GetHashCode(),
display_name.GetHashCode(),
is_visible.GetHashCode(),
is_collapsed.GetHashCode(),
font_weight_override.GetHashCode(),
font_color_override.GetHashCode(),
width.GetHashCode(),
horizontal_alignment.GetHashCode(),
horizontal_offset.GetHashCode(),
display_name.GetHashCode()
);
public override string ToString() {
return $"id: {id} display_name: {display_name}";
}
}
}
@@ -126,13 +126,15 @@ namespace mbts.ui {
col.set_fallback_font_params(new FontFamily(grid.font_family), grid.font_size, grid.font_color.rgb_color(), grid.font_weight);
_predicate_animations_data = value.predicate_animations;
_animation_defs.clear();
foreach (var pa in _predicate_animations_data) {
var predicate = pa.predicate_builder.create_predicate(_arg);
foreach (var s in pa.sound_notifications) {
_notification_subs.Add(_notification_service.link(predicate, s));
}
if (pa.predicate_builder is INotificationPredicateBuilder<TRowData, TPredicateBuilderArg> tpb && tpb.is_toast_enabled) {
_notification_subs.Add(_notification_service.link(tpb.create_notification_predicate(_arg)));
if (_notification_service != null && _arg != null) {
foreach (var pa in _predicate_animations_data) {
var predicate = pa.predicate_builder.create_predicate(_arg);
foreach (var s in pa.sound_notifications) {
_notification_subs.Add(_notification_service.link(predicate, s));
}
if (pa.predicate_builder is INotificationPredicateBuilder<TRowData, TPredicateBuilderArg> tpb && tpb.is_toast_enabled) {
_notification_subs.Add(_notification_service.link(tpb.create_notification_predicate(_arg)));
}
}
}
// ** in the unfortunate event that we botch backwards compatability, and the columns don't bear a 1:1 relationship with the column-settings
@@ -14,7 +14,7 @@ namespace mbts.spark.filters {
TimeFilterMode _mode;
TimeTextTuple _begin, _end;
DateTime? _begin_dt, _end_dt;
readonly DateTime _cme_open = MarketSchedule.get_cme_gen_open();
readonly DateTime _cme_open = MarketSchedule.get_start_of_trading_day();
public TimeFilterVM(Func<TRow, DateTime> get_row_val, string prop_name) : base(get_row_val, prop_name) =>
_set_default_values();
@@ -34,9 +34,11 @@ namespace bts.view.controls {
private void any_button_click(object sender, RoutedEventArgs e) {
Close();
}
internal static void Show(ErrorReportService srv, ErrorReport report) {
var window = new SupportRequestWindow(new SupportRequestVM(srv, report));
window.Show();
internal static void Show(ErrorReportService srv, ErrorReportImmutable? report) {
if (report.HasValue) {
var window = new SupportRequestWindow(new SupportRequestVM(srv, report.Value));
window.Show();
}
}
}
@@ -166,51 +166,6 @@
</Grid>
</DataTemplate>
</usp:OrderModificationTemplateSelector.TimeBoxOrderTemplate>
<usp:OrderModificationTemplateSelector.TickOrderTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="12"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="1" VerticalAlignment="Center">Cross Thresh</TextBlock>
<uag:QuantityMeasureControl Grid.Row="1" Grid.Column="2" QuantityMeasure="{Binding cross_threshold}"/>
<TextBlock Grid.Row="3" VerticalAlignment="Center">Cross Ticks</TextBlock>
<c:TickUpDownUInt Grid.Row="3" Grid.Column="2" Value="{Binding cross_ticks}"/>
<TextBlock Grid.Row="5" VerticalAlignment="Center">Max Chase Ticks</TextBlock>
<c:TickUpDownUInt Grid.Row="5" Grid.Column="2" Value="{Binding max_chase_ticks}"/>
<CheckBox Grid.Row="7" Grid.Column="2" VerticalAlignment="Center" Margin="0,0,0,0" IsChecked="{Binding detach_on_toward}">Detach on Toward</CheckBox>
<TextBlock Grid.Row="9" VerticalAlignment="Center">Initial Tick Offset</TextBlock>
<c:TickUpDownUInt Grid.Row="9" Grid.Column="2" Value="{Binding tick_offset_on_deploy}"/>
<TextBlock Grid.Row="11">Child</TextBlock>
<uag:OrderDetailsPopupControl
Grid.Row="11" Grid.Column="2"
IsOpen="{Binding child_order.editable_properties_open, FallbackValue=False}"
ItemsSource="{Binding child_order_types}"
SelectedItem="{Binding child_order}"
HasEditableProperties="{Binding child_order.has_editable_properties, FallbackValue=False}"
/>
</Grid>
</DataTemplate>
</usp:OrderModificationTemplateSelector.TickOrderTemplate>
<usp:OrderModificationTemplateSelector.LeanOrderTemplate>
<DataTemplate>
<Grid>
@@ -379,16 +334,16 @@
Orientation="Horizontal"
Grid.Row="1"
>
<TextBlock VerticalAlignment="Center" >Hedge Ticks</TextBlock>
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the number of ticks to offset the hedge." />
<TextBlock VerticalAlignment="Center" >Profit Ticks</TextBlock>
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the number of ticks in your favor to offset the profit/hedge order." />
</StackPanel>
<c:TickUpDownInt Grid.Row="1" Grid.Column="2" Value="{Binding hedge_ticks}"/>
<StackPanel
Orientation="Horizontal"
Grid.Row="3"
>
<TextBlock VerticalAlignment="Center">Hedge</TextBlock>
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the type of the hedge order to send for each fill of Child Order." />
<TextBlock VerticalAlignment="Center">Profit Order</TextBlock>
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the type of the profit/hedge order to send for each fill of Child Order." />
</StackPanel>
<uag:OrderDetailsPopupControl
Grid.Row="3" Grid.Column="2"
@@ -415,6 +370,68 @@
</Grid>
</DataTemplate>
</usp:OrderModificationTemplateSelector.CoverOrderTemplate>
<usp:OrderModificationTemplateSelector.OCOOrderTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="12"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="1" >
<TextBlock VerticalAlignment="Center" >Stop Ticks</TextBlock>
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the number of ticks away from the main order to start the 'stop' order." />
</StackPanel>
<c:TickUpDownInt Grid.Row="1" Grid.Column="2" Value="{Binding other_ticks}"/>
<StackPanel Orientation="Horizontal" Grid.Row="3" >
<TextBlock VerticalAlignment="Center" >Stop Side</TextBlock>
<c:HelpButton Margin="4,0,0,0" ToolTip="The Side of the 'stop' order" />
</StackPanel>
<ComboBox Grid.Row="3" Grid.Column="2" ItemsSource="{Binding other_side_types}" ItemTemplate="{StaticResource EnumDescriptionTemplate}" SelectedItem="{Binding other_side}"/>
<StackPanel
Orientation="Horizontal"
Grid.Row="5"
>
<TextBlock VerticalAlignment="Center">Stop Order</TextBlock>
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the type of the 'stop' order to send." />
</StackPanel>
<uag:OrderDetailsPopupControl
Grid.Row="5" Grid.Column="2"
IsOpen="{Binding other_order.editable_properties_open, FallbackValue=False}"
ItemsSource="{Binding other_order_types}"
SelectedItem="{Binding other_order}"
HasEditableProperties="{Binding other_order.has_editable_properties, FallbackValue=False}"
/>
<StackPanel
Orientation="Horizontal"
Grid.Row="7"
>
<TextBlock VerticalAlignment="Center">Child</TextBlock>
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the type of order to be placed when the algo is triggered." />
</StackPanel>
<uag:OrderDetailsPopupControl
Grid.Row="7" Grid.Column="2"
IsOpen="{Binding child_order.editable_properties_open, FallbackValue=False}"
ItemsSource="{Binding child_order_types}"
SelectedItem="{Binding child_order}"
HasEditableProperties="{Binding child_order.has_editable_properties, FallbackValue=False}"
/>
</Grid>
</DataTemplate>
</usp:OrderModificationTemplateSelector.OCOOrderTemplate>
<usp:OrderModificationTemplateSelector.OffsetOrderTemplate>
<DataTemplate>
<Grid>
@@ -773,9 +790,11 @@
</usp:DynamicOrderParamTemplateSelector>
</ItemsControl.ItemTemplateSelector>
</ItemsControl>
<TextBlock Grid.Row="3">Child</TextBlock>
<TextBlock Grid.Row="3"
Visibility="{Binding has_child, Converter={StaticResource BooleanToVisibilityConverter}}" >Child</TextBlock>
<uag:OrderDetailsPopupControl
Grid.Row="3" Grid.Column="2"
Grid.Row="3" Grid.Column="2"
Visibility="{Binding has_child, Converter={StaticResource BooleanToVisibilityConverter}}"
IsOpen="{Binding child_order.editable_properties_open, FallbackValue=False}"
ItemsSource="{Binding child_order_types}"
SelectedItem="{Binding child_order}"
@@ -0,0 +1,72 @@
<UserControl x:Class="mbts.ui.controls.PriceEntryCommitControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:u="clr-namespace:mbts.ui"
xmlns:cv="clr-namespace:mbts.ui.converters"
xmlns:uspcv="clr-namespace:mbts.ui.spark.converters"
xmlns:c="clr-namespace:mbts.ui.controls"
xmlns:usp="clr-namespace:mbts.ui.spark"
d:DesignHeight="100" d:DesignWidth="800" x:Name="_me_price">
<UserControl.Resources>
<cv:NullableDoubleConverter x:Key="TickDefaultPriceConverter" DefaultValue="0"/>
<uspcv:TickDisplayConverter x:Key="TickDisplayConverter" x:Shared="False"/>
<ControlTemplate x:Key="ReadTemplate">
<Grid HorizontalAlignment="Right" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.ColumnSpan="2">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource TickDisplayConverter}">
<Binding Path="SourceValue" ElementName="_me_price"/>
<Binding Path="SourceContractSpec" ElementName="_me_price"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="EditTemplate">
<Grid HorizontalAlignment="Right" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<usp:PriceEntryControl x:Name="price_ticker"
Margin="0,0,2,0"
TickDefaultValue="{Binding SourceValue, ElementName=_me_price, Converter={StaticResource TickDefaultPriceConverter}, FallbackValue={u:Double 0}}"
ContractSpec="{Binding SourceContractSpec, ElementName=_me_price}"
Value="{Binding SourceValue, ElementName=_me_price}" />
<Button Grid.Column="2" x:Name="commit_button" CommandParameter="{Binding Value, ElementName=price_ticker}" Command="{Binding OnCommit, ElementName=_me_price}" Content="✔" >
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="Background" Value="Green" />
<Setter Property="Foreground" Value="White" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Grid>
</ControlTemplate>
</UserControl.Resources>
<UserControl.Style>
<Style TargetType="UserControl">
<Setter Property="Template" Value="{StaticResource ReadTemplate}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding is_selected}" Value="True">
<Setter Property="Template" Value="{StaticResource EditTemplate}"/>
</DataTrigger>
<DataTrigger Binding="{Binding is_price_dirty}" Value="True">
<Setter Property="Template" Value="{StaticResource EditTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Style>
</UserControl>
@@ -0,0 +1,73 @@
using bts.api;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace mbts.ui.controls {
/// <summary>
/// Interaction logic for PriceEntryCommitControl.xaml
/// </summary>
public partial class PriceEntryCommitControl : UserControl {
public static readonly DependencyProperty SourceValueProperty =
DependencyProperty.Register("SourceValue",
typeof(double),
typeof(PriceEntryCommitControl),
new FrameworkPropertyMetadata {
BindsTwoWayByDefault = true,
PropertyChangedCallback = source_value_changed
}
);
public double SourceValue {
get => (double)GetValue(SourceValueProperty);
set => SetValue(SourceValueProperty, value);
}
private static void source_value_changed(DependencyObject d, DependencyPropertyChangedEventArgs e) {
if (d is PriceEntryCommitControl _instance_of_me) {
_instance_of_me.Dispatcher.BeginInvoke(
(Action)(() => _instance_of_me.OnCommit?.TryRaiseCanExecuteChanged())
);
}
}
public static readonly DependencyProperty SourceContractSpecProperty =
DependencyProperty.Register("SourceContractSpec", typeof(ContractSpecificationImmutable?), typeof(PriceEntryCommitControl));
public ContractSpecificationImmutable? SourceContractSpec {
get => (ContractSpecificationImmutable?)GetValue(SourceContractSpecProperty);
set => SetValue(SourceContractSpecProperty, value);
}
// public static readonly DependencyProperty PriceTextProperty =
//DependencyProperty.Register("PricText", typeof(string), typeof(PriceEntryCommitControl));
// public string PriceText {
// get => (string)GetValue(PriceTextProperty);
// set => SetValue(PriceTextProperty, value);
// }
public static readonly DependencyProperty OnCommitProperty =
DependencyProperty.Register("OnCommit", typeof(ICommand), typeof(PriceEntryCommitControl));
public ICommand OnCommit {
get => (ICommand)GetValue(OnCommitProperty);
set => SetValue(OnCommitProperty, value);
}
public PriceEntryCommitControl() {
InitializeComponent();
}
}
}
@@ -0,0 +1,55 @@
<UserControl x:Class="mbts.ui.controls.TickUpDownNullableUIntCommit"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:c="clr-namespace:mbts.ui.controls"
d:DesignHeight="100" d:DesignWidth="800" x:Name="_me">
<UserControl.Resources>
<ControlTemplate x:Key="ReadTemplate">
<Grid HorizontalAlignment="Right" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.ColumnSpan="2" Text="{Binding SourceValue, ElementName=_me}" />
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="EditTemplate">
<Grid HorizontalAlignment="Right" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<c:TickUpDownNullableUInt x:Name="qty_ticker" Margin="0,0,2,0" Value="{Binding SourceValue, ElementName=_me}" />
<Button Grid.Column="2" x:Name="commit_button" CommandParameter="{Binding Value, ElementName=qty_ticker}" Command="{Binding OnCommit, ElementName=_me}" Content="✔" >
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="Background" Value="Green" />
<Setter Property="Foreground" Value="White" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Grid>
</ControlTemplate>
</UserControl.Resources>
<UserControl.Style>
<Style TargetType="UserControl">
<Setter Property="Template" Value="{StaticResource ReadTemplate}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding is_selected}" Value="True">
<Setter Property="Template" Value="{StaticResource EditTemplate}"/>
</DataTrigger>
<DataTrigger Binding="{Binding is_qty_dirty}" Value="True">
<Setter Property="Template" Value="{StaticResource EditTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Style>
</UserControl>
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace mbts.ui.controls {
/// <summary>
/// Interaction logic for TickUpDownNullableUIntCommit.xaml
/// </summary>
public partial class TickUpDownNullableUIntCommit : UserControl {
public static readonly DependencyProperty SourceValueProperty =
DependencyProperty.Register("SourceValue",
typeof(uint?),
typeof(TickUpDownNullableUIntCommit),
new FrameworkPropertyMetadata {
BindsTwoWayByDefault = true,
PropertyChangedCallback = source_value_changed
}
);
private static void source_value_changed(DependencyObject d, DependencyPropertyChangedEventArgs e) {
if (d is TickUpDownNullableUIntCommit _instance_of_me) {
_instance_of_me.Dispatcher.BeginInvoke(
(Action)(() => _instance_of_me.OnCommit?.TryRaiseCanExecuteChanged())
);
}
}
public uint? SourceValue {
get => GetValue(SourceValueProperty) as uint?;
set => SetValue(SourceValueProperty, value);
}
public static readonly DependencyProperty OnCommitProperty =
DependencyProperty.Register("OnCommit", typeof(ICommand), typeof(TickUpDownNullableUIntCommit));
public ICommand OnCommit {
get => (ICommand)GetValue(OnCommitProperty);
set => SetValue(OnCommitProperty, value);
}
public TickUpDownNullableUIntCommit() {
InitializeComponent();
}
}
}
@@ -123,7 +123,7 @@ namespace mbts.spark {
return intpart + floatpart;
}
public static RegionalTickFactors get_regional_ticks(ContractSpecificationImmutable spec) =>
public static RegionalTickFactors get_regional_ticks(ContractSpecificationImmutable? spec) =>
TickStore.get(spec);
public static RegionalTickFactors get_regional_ticks(SecurityImmutable security) =>
@@ -177,8 +177,14 @@ namespace mbts.spark {
public static RegionalTickFactors get(ContractSpecification spec) =>
_exchange_ticks.GetOrAdd(new SpecKey(spec), _create_rtf);
public static RegionalTickFactors get(ContractSpecificationImmutable spec) =>
_exchange_ticks.GetOrAdd(new SpecKey(spec), _create_rtf);
public static RegionalTickFactors get(ContractSpecificationImmutable? spec) {
if (spec.HasValue) {
return _exchange_ticks.GetOrAdd(new SpecKey(spec.Value), _create_rtf);
}
else {
return null;
}
}
public static RegionalTickFactors get(SecurityImmutable security) =>
security.HasContractSpec ? get(security.ContractSpec) : default_rtf;
@@ -37,7 +37,7 @@ namespace mbts.spark {
readonly Property<Brush> _foreground, _background, _hoverbackground, _border, _parent_algo_type_brush;
readonly Property<bool> _is_exchange_order, _has_multiple_orders_at_same_level, _is_hedge_order;
readonly Property<CustomOrderDefinition.CustomOneofCase> _parent_algo_type;
readonly Property<string> _summary, _description;
readonly Property<string> _summary;
IObservable<LadderSettings.BadgeStyle> _bs;
LadderSettings.BadgeStyle _current_badge_style;
int _n_active_price_change_ops = 0;
@@ -63,7 +63,6 @@ namespace mbts.spark {
_hoverbackground = backing(nameof(hoverbackground), _color_bg_brush);
_border = backing(nameof(border), _color_bg_brush);
_summary = backing(nameof(summary), string.Empty);
_description = backing(nameof(description), string.Empty);
_is_exchange_order = backing(nameof(is_exchange_order), false);
_has_multiple_orders_at_same_level = backing(nameof(has_multiple_orders_at_same_level), false);
_is_hedge_order = backing(nameof(is_hedge_order), false);
@@ -75,6 +74,7 @@ namespace mbts.spark {
Brush get_foreground(LadderSettings s) => s.orders_column.foreground.rgb_brush();
//
add_order(o);
_dispose = Disposable.Create(
_bs.Subscribe(badge => {
_current_badge_style = badge;
@@ -122,7 +122,6 @@ namespace mbts.spark {
if (_orders.Any()) {
summary = _orders.Values.Select(order => order.short_description(_parent.security.ContractSpec)).Aggregate((s1, s2) => $"{s1}{Environment.NewLine}{Environment.NewLine}{s2}");
description = _orders.Values.Select(order => order.full_description(_parent.security)).Aggregate((s1, s2) => $"{s1}{Environment.NewLine}{Environment.NewLine}{s2}");
}
_set_badge_text();
@@ -185,11 +184,10 @@ namespace mbts.spark {
public Brush hoverbackground { get => _hoverbackground.Value; private set => _hoverbackground.Value = value; }
public Brush border { get => _border.Value; private set => _border.Value = value; }
public string summary { get => _summary.Value; private set => _summary.Value = value; }
public string description { get => _description.Value; private set => _description.Value = value; }
public bool is_exchange_order { get => _is_exchange_order.Value; private set => _is_exchange_order.Value = value; }
public bool has_multiple_orders_at_same_level { get => _has_multiple_orders_at_same_level.Value; private set => _has_multiple_orders_at_same_level.Value = value; }
public bool is_hedge_order { get => _is_hedge_order.Value; private set => _is_hedge_order.Value = value; }
public Brush parent_algo_type_brush { get => _parent_algo_type_brush.Value; private set => _parent_algo_type_brush.Value = value; }
public Brush parent_algo_type_brush { get => _parent_algo_type_brush.Value; private set => _parent_algo_type_brush.Value = value; }
// the setter is public so that the LadderVM can set this field
public CustomOrderDefinition.CustomOneofCase parent_algo_type { get => _parent_algo_type.Value; set => _parent_algo_type.Value = value; }
@@ -224,6 +222,56 @@ namespace mbts.spark {
}
}
public OrderBookVM create_orderbook_vm() {
// We are returning a new OrderBookVM each time b/c after
// successive launches of the mini-ob from the same badge, we get an exception
// System.InvalidOperationException: Sharing GridViewColumn among multiple GridViewColumnCollections or adding the same GridViewColumn into one GridViewColumnCollection more than once is not allowed.
// I checked with Eric and he guesses that what is happening is that the Popup is throwing away the grid, but the binding doesn't remove the columns from that grid
//
// I think returning a new OrderbookVM is okay at the moment since this Popup window will not be saving any state at this time
var price_filter = new filters.DoubleMinMaxState();
price_filter.minimum.value = real_price;
price_filter.maximum.value = real_price;
var obvm = new OrderBookVM(null, _parent.bus, null, _parent.model.order_gateway, null, true);
var state = new bts.shell.OrderBookWindowFactory.OrderBookStartupData(
new bts.shell.OrderBookWindowFactory.FilterStates {
security_criteria = new SecurityCriteria(_parent.security),
price = price_filter,
statuses = new[] { OrderStatus.Working }
},
bts.shell.OrderBookWindowFactory.OrderBookStartupData.default_mini_grid,
use_defaults: false
);
// NOTE:
// we might need the ObservableAppend to InsertAt
// if these EditXXX ever support settings.
// insert the cancel column
obvm.columns.Insert(0, new OrderBookVM.CancelColumn(nameof(OrderBookRowVM.cancel_command)));
var qty_col = obvm.columns.FirstOrDefault(x => x.id == OrderBookView.Columns.Size.ToString());
var qty_index = obvm.columns.indexOf(qty_col);
if (qty_index > -1) {
// insert the edit column in the same position that the hidden column occupies
var existing_editqty_col = obvm.columns.FirstOrDefault(x => x.id == OrderBookView.Columns.EditableQty.ToString());
var existing_editqty_index = obvm.columns.indexOf(existing_editqty_col);
if (existing_editqty_index == -1) {
obvm.columns.Insert(qty_index, new OrderBookVM.EditableQtyColumn());
}
}
var price_col = obvm.columns.FirstOrDefault(x => x.id == OrderBookView.Columns.Price.ToString());
var price_index = obvm.columns.indexOf(price_col);
if (price_index > -1) {
var existing_editprice_col = obvm.columns.FirstOrDefault(x => x.id == OrderBookView.Columns.EditablePrice.ToString());
var existing_editprice_index = obvm.columns.indexOf(existing_editprice_col);
if (existing_editprice_index == -1) {
// insert the edit price column immediately after the edit qty
obvm.columns.Insert(qty_index + 1, new OrderBookVM.EditablePriceColumn());
}
}
obvm.load_from(state);
return obvm;
}
public override string ToString() {
return $"Price: {this.price} Order Count: {this.orders.Count()}";
}
@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
@@ -91,15 +92,26 @@ namespace mbts.spark {
order.PropertyChanged += _order_PropertyChanged;
// get the stackpanel it belongs in
Panel panel = get_panel(price);
//var coords = GetAbsolutePlacement(panel, true);
// insert Badge and wire up DataContext
if (panel != null) {
panel.Children.Add(mkbadge(order));
panel.Children.Add(mkbadge(order, panel));
}
} //else {
//Log.Ui.warn($"Failed to add order ({order.id}): order already in {nameof(LadderGridHost)}'s {nameof(_orders)}.");
//}
}
public static Rect GetAbsolutePlacement(FrameworkElement element, bool relativeToScreen = false) {
var absolutePos = element.PointToScreen(new System.Windows.Point(0, 0));
if (relativeToScreen) {
return new Rect(absolutePos.X, absolutePos.Y, element.ActualWidth, element.ActualHeight);
}
var posMW = Application.Current.MainWindow.PointToScreen(new System.Windows.Point(0, 0));
absolutePos = new System.Windows.Point(absolutePos.X - posMW.X, absolutePos.Y - posMW.Y);
return new Rect(absolutePos.X, absolutePos.Y, element.ActualWidth, element.ActualHeight);
}
void _order_PropertyChanged(object sender, PropertyChangedEventArgs e) {
if (e.PropertyName == nameof(LadderOrderVM.price)) {
var order = (LadderOrderVM)sender;
@@ -108,35 +120,38 @@ namespace mbts.spark {
}
}
Badge mkbadge(LadderOrderVM order) {
Badge mkbadge(LadderOrderVM order, UIElement popup_placement_target) {
Badge b = new Badge();
b.DataContext = order;
// Hook up the style from xaml
b.Style = this.TryFindResource(typeof(Badge)) as Style;
b.MouseUp += (s, e) => {
b.MouseUp += async (s, e) => {
var curr_order = b.DataContext as LadderOrderVM;
if (e.ChangedButton == MouseButton.Middle) {
b.ContextMenu.DataContext = b.DataContext;
b.ContextMenu.IsOpen = true;
// close context menu after command executed
if (curr_order != null) {
Action command_executed = null;
command_executed = () => {
try {
b.ContextMenu.IsOpen = false;
curr_order.command_executed -= command_executed;
} catch (Exception ex) {
Log.Ui.warn($"Error in {typeof(LadderGridHost)}'s {typeof(Badge)} {nameof(LadderOrderVM.command_executed)} local handler: {ex}");
}
};
curr_order.command_executed += command_executed;
}
// create the new popup window in here
var obvm = order.create_orderbook_vm();
await Task.Delay(100); // Wait for obvm to load rows collection before showing UI to avoid a flash
var view = new MiniOrderBookView(obvm);
var popup = new System.Windows.Controls.Primitives.Popup {
// we only keep the obvm around assigned to the DataContext so that we can
// properly Dispose of it later when the popup is closed.
DataContext = obvm,
Child = view,
StaysOpen = false,
PlacementTarget = popup_placement_target,
Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom,
VerticalOffset = 5
};
popup.SetBinding(System.Windows.Controls.Primitives.Popup.IsOpenProperty,
nameof(OrderBookVM.is_row_collection_populated)
);
popup.Closed += (sender, event_args) => (popup.DataContext as IDisposable)?.Dispose();
b.Popup = popup;
} else if (e.ChangedButton == MouseButton.Left) {
if (curr_order?.cancel_command?.CanExecute(null) == true)
curr_order.cancel_command.Execute(null);
}
};
b.ContextMenuOpening += (s, e) => e.Handled = true;
return b;
}
@@ -181,6 +181,7 @@ namespace mbts.spark {
[ProtoContract]
class LadderSettings : IEquatable<LadderSettings> {
const double _default_order_entry_panel_width = 110.0;
const double _default_zoom_factor = 1.0;
// Default proto constructor
// Added this so that when clients upgrade to a version with new settings,
@@ -203,6 +204,7 @@ namespace mbts.spark {
auto_clear_visible = true;
clear_visible = true;
order_entry_panel_initial_width = _default_order_entry_panel_width;
zoom_factor = _default_zoom_factor;
use_defaults = true;
}
@@ -260,7 +262,9 @@ namespace mbts.spark {
cancel_all_visible = true,
auto_clear_visible = true,
clear_visible = true,
order_entry_panel_initial_width = _default_order_entry_panel_width
order_entry_panel_initial_width = _default_order_entry_panel_width,
zoom_slider_visible = false,
zoom_factor = _default_zoom_factor,
};
}
}
@@ -357,10 +361,19 @@ namespace mbts.spark {
public bool clear_visible { get; set; }
//
[ProtoMember(43), DefaultValue(_default_order_entry_panel_width)]
public double order_entry_panel_initial_width { get; set; }
public double order_entry_panel_initial_width { get; set; }
[ProtoMember(44), DefaultValue(true)]
public bool use_defaults { get; set; }
// the zoom slider is the first new widget on the panel
// since our initial general release, so its enablement
// will be opt-in (default not visible)
[ProtoMember(45)]
public bool zoom_slider_visible { get; set; }
[ProtoMember(46), DefaultValue(_default_zoom_factor)]
public double zoom_factor { get; set; }
public bool Equals(LadderSettings other) =>
other != null &&
row_height == other.row_height &&
@@ -403,6 +416,8 @@ namespace mbts.spark {
auto_clear_visible == other.auto_clear_visible &&
clear_visible == other.clear_visible &&
order_entry_panel_initial_width == other.order_entry_panel_initial_width &&
zoom_slider_visible == other.zoom_slider_visible &&
zoom_factor == other.zoom_factor &&
use_defaults == other.use_defaults;
public override bool Equals(object obj) => Equals(obj as LadderSettings);
@@ -449,16 +464,18 @@ namespace mbts.spark {
auto_clear_visible.GetHashCode(),
clear_visible.GetHashCode(),
order_entry_panel_initial_width.GetHashCode(),
zoom_slider_visible.GetHashCode(),
zoom_factor.GetHashCode(),
use_defaults.GetHashCode());
public struct WindowSpecifics {
public readonly double order_entry_panel_width;
public readonly double order_entry_panel_width, zoom_factor;
public readonly uint orders_column_width, bid_column_width, price_column_width, ask_column_width, last_column_width, volume_column_width;
public WindowSpecifics(LadderSettings s)
: this(s.order_entry_panel_initial_width, s.orders_column.width, s.bid_column.width, s.price_column.width, s.ask_column.width, s.last_column.width, s.volume_column.general.width) { }
: this(s.order_entry_panel_initial_width, s.orders_column.width, s.bid_column.width, s.price_column.width, s.ask_column.width, s.last_column.width, s.volume_column.general.width, s.zoom_factor) { }
public WindowSpecifics(double order_entry_panel_width, uint orders_column_width, uint bid_column_width, uint price_column_width, uint ask_column_width, uint last_column_width, uint volume_column_width) {
public WindowSpecifics(double order_entry_panel_width, uint orders_column_width, uint bid_column_width, uint price_column_width, uint ask_column_width, uint last_column_width, uint volume_column_width, double zoom_factor) {
this.order_entry_panel_width = order_entry_panel_width;
this.orders_column_width = orders_column_width;
this.bid_column_width = bid_column_width;
@@ -466,6 +483,7 @@ namespace mbts.spark {
this.ask_column_width = ask_column_width;
this.last_column_width = last_column_width;
this.volume_column_width = volume_column_width;
this.zoom_factor = zoom_factor;
}
}
}
@@ -496,6 +514,7 @@ namespace mbts.spark {
source.ask_column.width = specifics.ask_column_width;
source.last_column.width = specifics.last_column_width;
source.volume_column.general.width = specifics.volume_column_width;
source.zoom_factor = specifics.zoom_factor;
return source;
}
}
@@ -17,7 +17,7 @@ namespace mbts.spark {
readonly Property<LadderSettings.BadgeStyle> _badge_style;
readonly Property<uint> _alternate_order_size;
readonly DelegateProperty<double> _row_height;
Func<double> _get_order_entry_panel_width;
Func<double> _get_order_entry_panel_width, _get_zoom_factor;
LadderSettings _current;
LadderColumnSettingsVM
_orders = new OrdersColumnSettingsVM(),
@@ -34,6 +34,7 @@ namespace mbts.spark {
_session_high_mkt_line = new LadderMarketBreakLineVM("Session High", 2, 1, false),
_session_range_fill = new LadderMarketBreakLineVM("Session Range", 0, 0, false);
OrderEntryPanelItemVisibilityVM
_zoom_slider_visbility = new OrderEntryPanelItemVisibilityVM("Zoom Slider"),
_day_visibility = new OrderEntryPanelItemVisibilityVM("Day Change"),
_high_visibility = new OrderEntryPanelItemVisibilityVM("High"),
_low_visibility = new OrderEntryPanelItemVisibilityVM("Low"),
@@ -51,7 +52,7 @@ namespace mbts.spark {
_cancel_sells_visibility = new OrderEntryPanelItemVisibilityVM("Cancel Sells"),
_cancel_all_visibility = new OrderEntryPanelItemVisibilityVM("Cancel All");
public LadderSettingsVM(bool is_synthetic, Func<double> get_left_panel_width) {
public LadderSettingsVM(bool is_synthetic, Func<double> get_left_panel_width, Func<double> get_zoom_factor) {
this.is_synthetic = is_synthetic;
size_presets = new ObservableEditableCollection<IMutableValueWrapperVM<uint>>(_create_size_preset_vm);
size_presets.CollectionChanged += (s, e) => RaisePropertyChanged(nameof(size_presets_text));
@@ -59,6 +60,7 @@ namespace mbts.spark {
_badge_style.Changed += _badge_style_Changed;
_alternate_order_size = backing<uint>(nameof(alternate_order_size));
_get_order_entry_panel_width = get_left_panel_width;
_get_zoom_factor = get_zoom_factor;
// be sure to initialize backings before this measure_row_height call
_row_height = backing(nameof(row_height), () => LadderRender.measure_row_height(get_result()));
_orders.font_size_changed += on_font_size_changed;
@@ -130,6 +132,7 @@ namespace mbts.spark {
public IEnumerable<OrderEntryPanelItemVisibilityVM> order_entry_panel_items {
get {
yield return _zoom_slider_visbility;
yield return _day_visibility;
yield return _high_visibility;
yield return _low_visibility;
@@ -169,6 +172,7 @@ namespace mbts.spark {
_session_low_mkt_line.assign_from(_current.session_low_line);
_session_high_mkt_line.assign_from(_current.session_high_line);
_session_range_fill.assign_from(_current.session_range_fill);
_zoom_slider_visbility.show = settings.zoom_slider_visible;
_day_visibility.show = settings.day_visible;
_high_visibility.show = settings.high_visible;
_low_visibility.show = settings.low_visible;
@@ -227,6 +231,8 @@ namespace mbts.spark {
clone.cancel_sells_visible = _cancel_sells_visibility.show;
clone.cancel_all_visible = _cancel_all_visibility.show;
clone.order_entry_panel_initial_width = _get_order_entry_panel_width();
clone.zoom_slider_visible = _zoom_slider_visbility.show;
clone.zoom_factor = _get_zoom_factor();
return clone;
}
+13 -4
View File
@@ -24,12 +24,13 @@ namespace mbts.spark {
readonly IBus _bus;
readonly LadderModel _model;
readonly Property<double> _high, _low, _change, _open, _settlement, _position, _left_panel_width;
readonly Property<double> _high, _low, _change, _open, _settlement, _position, _left_panel_width, _zoom_factor;
//readonly Property<double> _window_width, _window_height;
readonly Property<uint> _orders_column_width, _bid_column_width, _price_column_width, _ask_column_width, _last_column_width, _volume_column_width;
readonly Property<ulong> _volume;
readonly Property<bool> _auto_clear, _show_day, _show_high, _show_low, _show_open, _show_settle, _show_volume, _show_account,
_show_tif, _show_order_type, _show_account_position, _show_size_preset, _show_auto_clear, _show_clear, _show_cancel_buys,
_show_cancel_sells, _show_cancel_all;
_show_cancel_sells, _show_cancel_all, _show_zoom;
readonly Property<Brush> _bid_background, _bid_foreground, _ask_background, _ask_foreground;
IWindowSettingsManager<LadderSettings> _settings_manager;
ulong _misc_time = 0;
@@ -58,6 +59,7 @@ namespace mbts.spark {
_last_column_width = backing(nameof(last_column_width), ws.last_column_width);
_volume_column_width = backing(nameof(volume_column_width), ws.volume_column_width);
_left_panel_width = backing(nameof(left_panel_width), ws.order_entry_panel_width);
_zoom_factor = backing(nameof(zoom_factor), ws.zoom_factor);
// remember: account_positions needs to subscribe to selected_account; both the sub and account_positions need to be disposed
var account_positions = new KeyDrivenObservableSeries<string, double>(a => _model.order_gateway.security_total_position(security.Id, a));
_position = backing(nameof(position), account_positions.OnDispatcher());
@@ -89,11 +91,14 @@ namespace mbts.spark {
_show_cancel_buys = bool_prop(nameof(show_cancel_buys), s => s.cancel_buys_visible);
_show_cancel_sells = bool_prop(nameof(show_cancel_sells), s => s.cancel_sells_visible);
_show_cancel_all = bool_prop(nameof(show_cancel_all), s => s.cancel_all_visible);
_show_zoom = bool_prop(nameof(show_zoom), s => s.zoom_slider_visible);
Property<bool> bool_prop(string name, Func<LadderSettings, bool> get_bool) =>
backing(name, settings_manager.subscribe_current().OnDispatcher(), get_bool);
//
//_window_height = backing(nameof(window_height), settings_manager.subscribe_current().OnDispatcher().Select(s => s.zoom_factor), (scale) => scale * 600);
//_window_width = backing(nameof(window_width), settings_manager.subscribe_current().OnDispatcher().Select(s => s.zoom_factor), (scale) => scale * 420);
position_click_command = new DelegateCommand(() => size_calculator.value = DoubleHelper.safe_convert_to_uint(Math.Abs(position)));
send_order_command = new DelegateCommand<(double price, Side? side, bool size_from_alternate)>(send_order);
cancel_command = new AsyncCommand<LadderModel.CancelType>(_model.cancel_orders, true);
@@ -103,7 +108,7 @@ namespace mbts.spark {
var vm = new WindowSettingsDialogVM<LadderSettings, LadderSettingsVM>(
settings_manager, s => s.ladder, UserSettings.FileExtensions.LADDER,
s => {
var svm = new LadderSettingsVM(security.ContractCase == Security.ContractOneofCase.Synthetic, () => left_panel_width);
var svm = new LadderSettingsVM(security.ContractCase == Security.ContractOneofCase.Synthetic, () => left_panel_width, () => zoom_factor);
svm.load(s);
return svm;
}, s => s.with_window_specifics(get_save_state().get_window_specifics()));
@@ -284,7 +289,11 @@ namespace mbts.spark {
public bool show_cancel_buys { get => _show_cancel_buys.Value; set => _show_cancel_buys.set(value); }
public bool show_cancel_sells { get => _show_cancel_sells.Value; set => _show_cancel_sells.set(value); }
public bool show_cancel_all { get => _show_cancel_all.Value; set => _show_cancel_all.set(value); }
public bool show_zoom { get => _show_zoom.Value; set => _show_zoom.set(value); }
public double left_panel_width { get => _left_panel_width.Value; set => _left_panel_width.set(value); }
public double zoom_factor { get => _zoom_factor.Value; set => _zoom_factor.set(value); }
//public double window_height { get => _window_height.Value; set => _window_height.set(value); }
//public double window_width { get => _window_width.Value; set => _window_width.set(value); }
public uint orders_column_width { get => _orders_column_width.Value; set => _orders_column_width.set(value); }
public uint bid_column_width { get => _bid_column_width.Value; set => _bid_column_width.set(value); }
public uint price_column_width { get => _price_column_width.Value; set => _price_column_width.set(value); }
@@ -296,7 +305,7 @@ namespace mbts.spark {
public LadderSettings get_save_state() {
var state = _settings_manager.current_settings();
state = state.with_window_specifics(new LadderSettings.WindowSpecifics(left_panel_width, orders_column_width, bid_column_width, price_column_width, ask_column_width, last_column_width, volume_column_width));
state = state.with_window_specifics(new LadderSettings.WindowSpecifics(left_panel_width, orders_column_width, bid_column_width, price_column_width, ask_column_width, last_column_width, volume_column_width, zoom_factor));
state.use_defaults = _settings_manager.instance_settings == null;
return state;
}
@@ -9,6 +9,7 @@
xmlns:uag="clr-namespace:mbts.ui.spark.algo"
xmlns:converters="clr-namespace:mbts.ui.converters"
xmlns:txt="clr-namespace:mbts.ui.utility.text"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Height="600"
Width="420"
Background="{x:Static mbts:BTSColors.common_background_brush}"
@@ -273,10 +274,18 @@
</Setter.Value>
</Setter>
</Style>
<sys:Double x:Key="MaxZoomFactor">1.5</sys:Double>
<sys:Double x:Key="MinZoomFactor">0.5</sys:Double>
</ResourceDictionary>
</UserControl.Resources>
<AdornerDecorator>
<Grid x:Name="_root">
<Grid.LayoutTransform>
<ScaleTransform CenterX="0" CenterY="0"
ScaleX="{Binding ElementName=_ui_scaler, Path=Value}"
ScaleY="{Binding ElementName=_ui_scaler, Path=Value}"
/>
</Grid.LayoutTransform>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding left_panel_width, Mode=TwoWay, Converter={StaticResource GridLengthPixelConverter}}"
MinWidth="60" MaxWidth="150"/>
@@ -298,6 +307,13 @@
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
</StackPanel.Resources>
<StackPanel x:Name="_slider_stack_panel" Margin="5,5,5,0">
<Slider x:Name="_ui_scaler" Value="{Binding zoom_factor}"
Minimum="{StaticResource MinZoomFactor}"
Maximum="{StaticResource MaxZoomFactor}"
Width="{Binding Path=ActualWidth, ElementName=_slider_stack_panel}"
Visibility="{Binding show_zoom, Converter={StaticResource BooleanToVisibilityConverter}}"/>
</StackPanel>
<Grid Margin="2,4,2,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
@@ -517,29 +533,12 @@
<Setter Property="Foreground" Value="{Binding foreground}"/>
<Setter Property="TextLines" Value="{Binding text_lines}" />
<Setter Property="Width" Value="{x:Static controls:Badge.DefaultWidth}"/>
<Setter Property="ToolTip" Value="{Binding description}" />
<Setter Property="IsExchangeOrder" Value="{Binding is_exchange_order}" />
<Setter Property="HasMultipleOrdersAtLevel" Value="{Binding has_multiple_orders_at_same_level}" />
<Setter Property="IsHedgeOrder" Value="{Binding is_hedge_order}" />
<Setter Property="ParentAlgoType" Value="{Binding parent_algo_type}" />
<Setter Property="ParentAlgoTypeBrush" Value="{Binding parent_algo_type_brush}" />
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Command="{Binding cancel_command}" Header="Cancel">
<MenuItem.Icon>
<Image Source="{StaticResource CancelSelected}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Command="{Binding detach_command}" Header="Detach">
<MenuItem.Icon>
<Image Source="{StaticResource ModifyOrder}" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{Binding hoverbackground}" />
@@ -5,9 +5,12 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
namespace mbts.spark {
partial class LadderView : UserControl {
readonly double _max_zoom, _min_zoom;
internal LadderView(LadderVM vm) {
InitializeComponent();
_column_headers_presenter.Columns = new GridViewColumnCollection();
@@ -16,8 +19,58 @@ namespace mbts.spark {
this.vm = vm;
DataContext = vm;
DataContextChanged += datacontext_changed;
if (TryFindResource("MaxZoomFactor") is double found_max) {
_max_zoom = found_max;
} else {
// is there a better way of not specifying the constant twice ?
// once in the resource dictionary here and again in the xaml, seems like there has to be a better way
_max_zoom = 1.5;
}
// ditto
if (TryFindResource("MinZoomFactor") is double found_min) {
_min_zoom = found_min;
} else {
_min_zoom = 0.5;
}
_ui_scaler.MouseDoubleClick += _ui_scaler_MouseDoubleClick;
this.PreviewMouseWheel += LadderView_PreviewMouseWheel;
this.PreviewMouseDown += LadderView_PreviewMouseDown;
}
// (Left|Right) CTRL + Wheel to zoom
// This is neat b/c the user doesn't even need to have the slider visible to zoom
private void LadderView_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e) {
base.OnPreviewMouseWheel(e);
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) {
var delta = (e.Delta > 0) ? 0.1 : -0.1;
var proposed_scaler_value = _ui_scaler.Value + delta;
// Here we enforce the same contraints that are on the gui slider regarding min and max
if (_min_zoom < proposed_scaler_value && proposed_scaler_value < _max_zoom) {
_ui_scaler.Value = proposed_scaler_value;
}
}
}
// (Left|Right) CTRL + Wheel Click to reset
private void LadderView_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
base.OnPreviewMouseDown(e);
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) {
if (e.MiddleButton == MouseButtonState.Pressed) {
_ui_scaler_MouseDoubleClick(_ui_scaler, e);
}
}
}
// Double click on scaler itself to reset
private void _ui_scaler_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e) {
if (sender is Slider _the_slider) {
_the_slider.Value = 1.0;
}
}
private void datacontext_changed(object sender, DependencyPropertyChangedEventArgs e) {
this.vm = DataContext as LadderVM;
}
@@ -28,31 +28,10 @@ namespace mbts.spark {
static readonly int sod_hh = (int)config.Configuration.get<bts.config.SODTime>().sod_hh;
static readonly int sod_mm = (int)config.Configuration.get<bts.config.SODTime>().sod_mm;
static readonly TimeZoneInfo central_tzi = TimeZoneInfo.FindSystemTimeZoneById(cst_id);
static readonly DateTime _start_of_trading_day_utc;
static readonly DateTime _adjusted_central_sod;
static readonly DateTime unadjusted_central_sod = TimeZoneInfo.ConvertTimeFromUtc(
DateTime.UtcNow.Date.Add(new TimeSpan(sod_hh, sod_mm, 0)),
central_tzi
);
static MarketSchedule() {
var cme_schedule = config.Configuration.get<bts.md.CMETradingSchedule>();
_cme_gen_open_hrs = cme_schedule?.gen_open_hour ?? 8.5;
_adjusted_central_sod = !central_tzi.IsDaylightSavingTime(unadjusted_central_sod) ? unadjusted_central_sod.AddHours(1) : unadjusted_central_sod;
// Note that this isn't the acutal start of the trading day
// but it's close enough for pnl purposes.
// In reality, instruments have different schedules
// if now is less than the current sod, then we me move the sod back a day to account for the trading day start
if (_adjusted_central_sod >= TimeZoneInfo.ConvertTime(DateTime.Now, central_tzi)) {
_adjusted_central_sod = _adjusted_central_sod.AddDays(-1);
}
var local_time_zone_sod = TimeZoneInfo.ConvertTime(_adjusted_central_sod, central_tzi, TimeZoneInfo.Local);
_start_of_trading_day_utc = local_time_zone_sod.ToUniversalTime();
}
// for object initializers
public MarketSchedule() { }
@@ -73,6 +52,27 @@ namespace mbts.spark {
return last_open;
}
// DateTime? used here b/c we can't set a default parameter with DateTime.Now
// since it's not a compile-time constant
public static DateTime get_start_of_trading_day(DateTime? target_datetime = null, DateTimeKind dtk = DateTimeKind.Local ) {
if (target_datetime == null) target_datetime = DateTime.Now;
var dst_adjusted_central_sod = new DateTimeOffset(
new DateTime(target_datetime.Value.Date.Add(new TimeSpan(sod_hh, sod_mm, 0)).Ticks, DateTimeKind.Unspecified),
central_tzi.BaseUtcOffset
);
// if we're not currently past the start of the trading day, then the start must be yesterday
var temp = dst_adjusted_central_sod;
if (temp >= TimeZoneInfo.ConvertTime(target_datetime.Value, central_tzi)) {
temp = dst_adjusted_central_sod.AddDays(-1);
}
var local_time_zone_sod = TimeZoneInfo.ConvertTime(temp.DateTime, central_tzi, TimeZoneInfo.Local);
if (dtk == DateTimeKind.Utc) {
return local_time_zone_sod.ToUniversalTime();
}
return local_time_zone_sod;
}
public static DateTime get_utctimestamp_as_localtime(string s) {
return DateTimeOffset.ParseExact(s, "yyyyMMddHHmmssffffff", null, System.Globalization.DateTimeStyles.AssumeUniversal).ToLocalTime().LocalDateTime;
}
@@ -25,7 +25,6 @@ namespace mbts.spark.utilities {
static readonly OrderMetadata _default_order_metadata = new OrderMetadata { KeyBinding = "", Color = BTSColors.Orders.spreader_order };
static readonly CustomOrderDefinition.CustomOneofCase[]
// The following standard types are not yet ready for production use:
// CustomOrderDefinition.CustomOneofCase.Tick,
// CustomOrderDefinition.CustomOneofCase.Dynamic,
_standard_types = new[] {
CustomOrderDefinition.CustomOneofCase.Market,
@@ -37,6 +36,7 @@ namespace mbts.spark.utilities {
CustomOrderDefinition.CustomOneofCase.Lean,
CustomOrderDefinition.CustomOneofCase.Join,
CustomOrderDefinition.CustomOneofCase.Cover,
CustomOrderDefinition.CustomOneofCase.Oco,
CustomOrderDefinition.CustomOneofCase.Offset,
CustomOrderDefinition.CustomOneofCase.Top,
CustomOrderDefinition.CustomOneofCase.Trigger,
@@ -165,7 +165,8 @@ namespace mbts.spark.utilities {
}
#endregion
public OrderDefinition order(SecurityImmutable security) => order(security, _admin_model.get_default_account());
public OrderDefinitionImmutable order(SecurityImmutable security) =>
new OrderDefinitionImmutable(order(security, _admin_model.get_default_account()));
public OrderDefinition order(SecurityImmutable security, AccountTuple? account) {
var rv = new OrderDefinition {
SecurityKey = security.Id,
@@ -227,6 +228,15 @@ namespace mbts.spark.utilities {
Child = custom_order(),
Hedge = custom_order(),
};
public OCOOrderDefinition oco_order() => new OCOOrderDefinition
{
Child = custom_order(),
Other = custom_order(),
};
public PricerOrderDefinition pricer_order() => new PricerOrderDefinition
{
Child = custom_order(),
};
public OffsetOrderDefinition offset_order() => new OffsetOrderDefinition
{
Child = custom_order(),
@@ -261,6 +271,8 @@ namespace mbts.spark.utilities {
case CustomOrderDefinition.CustomOneofCase.Join: rv.Join = join_order(); break;
case CustomOrderDefinition.CustomOneofCase.Top: rv.Top = top_order(); break;
case CustomOrderDefinition.CustomOneofCase.Cover: rv.Cover = cover_order(); break;
case CustomOrderDefinition.CustomOneofCase.Oco: rv.Oco = oco_order(); break;
case CustomOrderDefinition.CustomOneofCase.Pricer: rv.Pricer = pricer_order(); break;
case CustomOrderDefinition.CustomOneofCase.Offset: rv.Offset = offset_order(); break;
case CustomOrderDefinition.CustomOneofCase.Trigger: rv.Trigger = trigger_order(); break;
case CustomOrderDefinition.CustomOneofCase.Spreader: rv.Spreader = spreader_order(); break;
@@ -284,6 +296,8 @@ namespace mbts.spark.utilities {
case CustomOrderDefinition.CustomOneofCase.Join: return new OrderMetadata { KeyBinding = "J", Color = BTSColors.Orders.join_order };
case CustomOrderDefinition.CustomOneofCase.Top: return new OrderMetadata { KeyBinding = "D", Color = BTSColors.Orders.top_order };
case CustomOrderDefinition.CustomOneofCase.Cover: return new OrderMetadata { KeyBinding = "C", Color = BTSColors.Orders.cover_order };
case CustomOrderDefinition.CustomOneofCase.Oco: return new OrderMetadata { KeyBinding = "C", Color = BTSColors.Orders.oco_order };
case CustomOrderDefinition.CustomOneofCase.Pricer: return new OrderMetadata { KeyBinding = "C", Color = BTSColors.Orders.pricer_order };
case CustomOrderDefinition.CustomOneofCase.Offset: return new OrderMetadata { KeyBinding = "O", Color = BTSColors.Orders.tick_order };
case CustomOrderDefinition.CustomOneofCase.Trigger: return new OrderMetadata { KeyBinding = "T", Color = BTSColors.Orders.trigger_order };
case CustomOrderDefinition.CustomOneofCase.Spreader: goto default;
@@ -305,6 +319,8 @@ namespace mbts.spark.utilities {
case OrderState.CustomOneofCase.Join: return new OrderMetadata { KeyBinding = "J", Color = BTSColors.Orders.join_order };
case OrderState.CustomOneofCase.Top: return new OrderMetadata { KeyBinding = "D", Color = BTSColors.Orders.top_order };
case OrderState.CustomOneofCase.Cover: return new OrderMetadata { KeyBinding = "C", Color = BTSColors.Orders.cover_order };
case OrderState.CustomOneofCase.Oco: return new OrderMetadata { KeyBinding = "C", Color = BTSColors.Orders.oco_order };
case OrderState.CustomOneofCase.Pricer: return new OrderMetadata { KeyBinding = "C", Color = BTSColors.Orders.pricer_order };
case OrderState.CustomOneofCase.Offset: return new OrderMetadata { KeyBinding = "O", Color = BTSColors.Orders.tick_order };
case OrderState.CustomOneofCase.Trigger: return new OrderMetadata { KeyBinding = "T", Color = BTSColors.Orders.trigger_order };
case OrderState.CustomOneofCase.Spreader: goto default;
@@ -344,6 +360,8 @@ namespace mbts.spark.utilities {
case nameof(JoinOrderDefinition): return CustomOrderDefinition.CustomOneofCase.Join;
case nameof(TopOrderDefinition): return CustomOrderDefinition.CustomOneofCase.Top;
case nameof(CoverOrderDefinition): return CustomOrderDefinition.CustomOneofCase.Cover;
case nameof(OCOOrderDefinition): return CustomOrderDefinition.CustomOneofCase.Oco;
case nameof(PricerOrderDefinition): return CustomOrderDefinition.CustomOneofCase.Pricer;
case nameof(OffsetOrderDefinition): return CustomOrderDefinition.CustomOneofCase.Offset;
case nameof(TriggerOrderDefinition): return CustomOrderDefinition.CustomOneofCase.Trigger;
case nameof(DynamicOrderDefinition): return CustomOrderDefinition.CustomOneofCase.Dynamic;
+1 -1
View File
@@ -54,7 +54,7 @@ namespace bts.md
{
foreach (var v in values)
{
var smd = new SecurityMD(v.security, v.handle);
var smd = new SecurityMD(new SecurityImmutable(v.security), v.handle);
_exchange_sec_map.AddOrUpdate(smd.security.Id, smd, (_, __) => smd);
}
_version += 1;
@@ -37,17 +37,17 @@ namespace bts.api {
$"{symbol}{DateFormatter.Format(future.ExpirationYear, future.ExpirationMonth, future.ExpirationDay, DateFormat.MonthCodeLastDigitYear)}" :
exch_desc;
static string _format(SecurityImmutable security) {
switch (security.ContractCase) {
case ContractOneofCase.Future: return format_future(security.Symbol, security.glbx_desc(), security.Future);
static string _format(SecurityImmutable? security) {
switch (security?.ContractCase) {
case ContractOneofCase.Future: return format_future(security?.Symbol, security?.glbx_desc(), security.Value.Future);
case ContractOneofCase.Spread:
if (security.HasGlbx) {
if (security?.HasGlbx == true) {
// In case we ever bring it back, pretty printed spread names can be found here:
// GlbxSecurityFormatter.FormatSpread(security, out string result)
return security.Glbx.SecurityDesc;
return security?.Glbx.SecurityDesc;
}
return string.Join("", _format_future_legs(SecurityHelper.get_flat_future_legs(security.Spread.Legs)));
case ContractOneofCase.Synthetic: return security.Synthetic.Name;
return string.Join("", _format_future_legs(SecurityHelper.get_flat_future_legs(security?.Spread.Legs)));
case ContractOneofCase.Synthetic: return security?.Synthetic.Name;
default: return "Unknown-security";
}
}
@@ -66,24 +66,10 @@ namespace bts.api {
public static readonly IComparer<SecurityImmutable> InstanceImmutable = Comparer<SecurityImmutable>.Create(Compare);
public static int Compare(Security x, Security y) {
if (x.ContractCase == ContractOneofCase.Future) return y.ContractCase == ContractOneofCase.Future ? Compare(x.Symbol, x.Future, y.Symbol, y.Future) : -1;
else if (y.ContractCase == ContractOneofCase.Future) return 1;
var xlegs = get_flat_future_legs(x).ToList();
var ylegs = get_flat_future_legs(y).ToList();
int max = Math.Min(xlegs.Count, ylegs.Count);
for (int i = 0; i < max; i++) {
int rv = Compare(xlegs[i].symbol, xlegs[i].future, ylegs[i].symbol, ylegs[i].future);
if (rv != 0) return rv;
}
for (int i = 0; i < max; i++) {
int rv = xlegs[i].quantity.CompareTo(ylegs[i].quantity);
if (rv != 0) return rv;
}
for (int i = 0; i < max; i++) {
int rv = xlegs[i].exchange.CompareTo(ylegs[i].exchange);
if (rv != 0) return rv;
}
return xlegs.Count.CompareTo(ylegs.Count);
if (ReferenceEquals(x, y)) return 0; // x ==y
if (x == null) return 1; // y > x
if (y == null) return -1; // x > y
return Compare(new SecurityImmutable(x), new SecurityImmutable(y));
}
public static int Compare(SecurityImmutable x, SecurityImmutable y) {
+1 -1
View File
@@ -15,7 +15,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.4.0" />
<PackageReference Include="Google.Protobuf" Version="3.6.1" />
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
<PackageReference Include="System.Reactive" Version="3.1.1" />
</ItemGroup>
+1
View File
@@ -5,6 +5,7 @@ using System.Runtime.InteropServices;
namespace bts {
enum Level {
NoLog,
Diag,
Info,
Warn,
+88 -38
View File
@@ -61,7 +61,7 @@ namespace bts.collections {
if (_nursery.TryPopValue(k, out SortedList<Node> children)) {
// remove orphans from _tree (orphan-nodes must reside in the main _tree until parents arrive)
foreach (var n in children)
_tree.Remove(n);
_assert_remove(_tree, n);
node = new Node(item, children);
} else node = new Node(item, _comparer);
var pk = parent(item);
@@ -84,13 +84,10 @@ namespace bts.collections {
if (!_index.TryGetValue(k, out Node node)) {
return false;
} else {
var newval = replace(node.value);
Log.assert(id(newval).Equals(k));
_replace(node, newval);
_replace(node, replace);
return true;
}
}
public void Remove(T item) => Remove(id(item));
@@ -185,44 +182,97 @@ namespace bts.collections {
}
}
void _replace(Node node, T newval) {
TKey pk = parent(newval);
TKey old_pk = parent(node.value);
if (pk.Equals(old_pk)) {
SortedList<Node> node_list;
if (pk.Equals(_root_id))
node_list = _tree;
else if (_index.TryGetValue(pk, out Node pnode)) {
node_list = pnode.children;
} else if (!_nursery.TryGetValue(pk, out node_list)) {
throw new KeyNotFoundException($"Replace was called with a parent-key ({pk}) that was not found in _index or _nursery; item-key was ({id(newval)}).");
}
node_list.Remove(node);
node.value = newval;
node_list.Add(node);
} else {
if (old_pk.Equals(_root_id)) {
_tree.Remove(node);
} else {
if (_index.TryGetValue(old_pk, out Node pnode))
pnode.children.Remove(node);
else {
_remove_from_nursery(old_pk, node);
}
}
node.value = newval;
if (pk.Equals(_root_id)) {
void _replace(Node node, T new_value) =>
_replace(node, _ => new_value);
void _replace(Node node, Func<T, T> replace_value) {
/// STEPS (outline)
/// 1) remove node with current value
/// 2) replace node.value
/// 3) re-insert node with new value
/// Implementation (details):
/// there are 3 scenarios in which step 1 (remove node...) may occur
/// a) node is a root node
/// - remove it from <see cref="_tree"/>.
/// b) node is a child node who's parent is present
/// - remove it from the parent <see cref="Node.children"/>
/// c) the node is a child node who's parent is NOT present
/// - remove it from <see cref="_nursery"/> AND <see cref="_tree"/>.
/// In each scenario, after the node is removed, the new parent will be assigned (<see cref="new_pk"/>).
/// If the parent has NOT changed, assign the node back to the same list(s), then return.
/// If the parent HAS changed, determine the list(s) in which the node needs to be inserted, insert the node, then return.
TKey old_pk = parent(node.value), new_pk;
if (old_pk.Equals(_root_id)) {
// a)
_assert_remove(_tree, node);
_assert_replace(ref node, replace_value);
new_pk = parent(node.value);
if (new_pk.Equals(old_pk)) {
// the parent has NOT changed; re-insert the node, then return.
_tree.Add(node);
} else if (_index.TryGetValue(pk, out Node pnode)) {
pnode.children.Add(node);
} else {
if (!_nursery.TryGetValue(pk, out SortedList<Node> nursery_list)) {
_nursery.Add(pk, nursery_list = new SortedList<Node>(_comparer));
}
return;
}
} else if (_index.TryGetValue(old_pk, out Node old_pnode)) {
// b)
_assert_remove(old_pnode.children, node);
_assert_replace(ref node, replace_value);
new_pk = parent(node.value);
if (new_pk.Equals(old_pk)) {
// the parent has NOT changed; re-insert the node, then return.
old_pnode.children.Add(node);
return;
}
} else if (_nursery.TryGetValue(old_pk, out SortedList<Node> nursery_list)) {
// c)
_assert_remove(nursery_list, node);
_assert_remove(_tree, node);
_assert_replace(ref node, replace_value);
new_pk = parent(node.value);
if (new_pk.Equals(old_pk)) {
// the parent has NOT changed; re-insert the node, then return.
nursery_list.Add(node);
_tree.Add(node);
return;
} else {
// the parent HAS changed; if the old nursery_list is empty, remove it.
if (nursery_list.Count == 0)
_nursery.Remove(old_pk);
}
} else {
// error)
throw new InvalidOperationException($"Unknown parent key '{old_pk}'.");
}
// the parent HAS changed. Determine the list(s) in which the node needs to inserted.
if (new_pk.Equals(_root_id)) {
_tree.Add(node);
} else if (_index.TryGetValue(new_pk, out Node new_pnode)) {
new_pnode.children.Add(node);
} else {
if (!_nursery.TryGetValue(new_pk, out SortedList<Node> new_nursery_list)) {
_nursery.Add(new_pk, new_nursery_list = new SortedList<Node>(_comparer));
}
new_nursery_list.Add(node);
_tree.Add(node);
}
}
/// <summary>
/// Attempts to removes the node from the list <see cref="SortedList{T}.Remove"/> and throws an exception if it does not succeed.
/// </summary>
static void _assert_remove(SortedList<Node> list, Node node) {
if (!list.Remove(node))
throw new InvalidOperationException("Failed to remove node.");
}
/// <summary>
/// Replaces <see cref="Node.value"/> using the specified delegate, and throws an exception if the new value's id is different from the old value's id.
/// </summary>
void _assert_replace(ref Node node, Func<T, T> replace_value) {
TKey old_key = id(node.value);
node.value = replace_value(node.value);
if (!id(node.value).Equals(old_key))
throw new InvalidOperationException("Replace op changed Node's id.");
}
void _remove_from_nursery(TKey pk, Node node) {
@@ -9,12 +9,12 @@ using System.Threading.Tasks;
namespace bts.test {
public static class InProcessTestRunner {
public static void run_test_syncronously(string v, TestEnumerator enumerator, Action<TestResult> report) {
public static void run_test_synchronously(string v, TestEnumerator enumerator, Action<TestResult> report) {
foreach (var t in enumerator.find(v)) {
run_test_syncronously(t, report);
run_test_synchronously(t, report);
}
}
public static void run_test_syncronously(TestMethod test, Action<TestResult> report) {
public static void run_test_synchronously(TestMethod test, Action<TestResult> report) {
var result = new TestResult() {
TestName = test.full_name,
Status = TestResult.Types.Step.Setup,
@@ -2,8 +2,16 @@
namespace bts.test {
public enum TestType {
Unit, System, Shell
}
[AttributeUsage(AttributeTargets.Class)]
public class TestGroupAttribute : Attribute {
public TestGroupAttribute() {
this.TestType = TestType.Unit;
}
public TestType TestType;
}
[AttributeUsage(AttributeTargets.Method)]
public class TestAttribute : Attribute {
@@ -7,23 +7,34 @@ namespace bts.test {
public class TestEnumerator {
public TestEnumerator(params string[] assemblies) {
TestGroups =
TestGroups =
assemblies
.Select(Assembly.Load)
.SelectMany(a => a.GetTypes())
.Where(t => t.GetCustomAttribute<TestGroupAttribute>() != null)
.Select(t =>
new TestClass(t,
new TestClass(t,
t.GetCustomAttribute<TestGroupAttribute>().TestType,
t.GetMethods()
.Where(m => m.GetCustomAttribute<TestAttribute>() != null)
.Select(m => new TestMethod(t, m))
.ToList()))
.ToList();
.ToList();
}
public IReadOnlyCollection<TestClass> TestGroups { get; }
public IEnumerable<TestClass> get_groups_of_type(TestType tt) {
return TestGroups.Where(wt => wt.test_type == tt);
}
public IEnumerable<TestMethod> Tests => TestGroups.SelectMany(t => t.methods);
public IEnumerable<TestMethod> get_of_type(TestType tt) {
return TestGroups.Where(wt => wt.test_type == tt).SelectMany(t => t.methods);
}
public IEnumerable<TestMethod> find(string name) {
foreach (var g in TestGroups) {
foreach (var t in g.methods) {
@@ -41,13 +52,15 @@ namespace bts.test {
public class TestClass {
public TestClass(Type type, IEnumerable<TestMethod> methods) {
public TestClass(Type type, TestType test_type, IEnumerable<TestMethod> methods) {
this.type = type;
this.test_type = test_type;
this.methods = methods;
}
public string name => type.Name;
public Assembly assembly => type.Assembly;
public Type type { get; }
public TestType test_type { get; }
public IEnumerable<TestMethod> methods { get; }
public override string ToString() {
return $"[TestGroup:{name}]";
+1 -1
View File
@@ -21,7 +21,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.4.0" />
<PackageReference Include="Google.Protobuf" Version="3.6.1" />
<PackageReference Include="System.Reactive" Version="3.1.1" />
<PackageReference Include="System.Reactive.PlatformServices" Version="3.1.1" />
<PackageReference Include="NUnit" Version="3.10.1" />
+30 -14
View File
@@ -1,8 +1,31 @@
# BTS Spark
Our offering consists of a client UI [Spark Client](https://www.bluetradingsystems.com/images/Images/spark/02.06.19/Ladder.png), a high performance professional futures front end, connected via our proprietary protocol over TCP to our Spark Server, which in turn connects to execution venues via their native protocols (typically FIX/TCP for execution and some proprietary protocol over UDP multicast for market data).
![alt text](https://www.bluetradingsystems.com/images/Images/api/API.png)
# BTS Spark Client SDK
#### Getting Started
We currently offer two API extension points. This repository, our BTS **Spark Client SDK** allows users to control our Spark Server externally, that is, out of process, using the exact same protocol our own Spark Client does. In other words, a client application developed via the Spark Client SDK, say a VB .NET UI, would be able to provide any functionality our own UI provides.
## Git
We currently offer bindings for the Spark protocol to C++, C# and Excel clients. Since the underlying transport is TCP, clients developed via the Spark Client SDK can be located anywhere in the world, as long as they can reach the Spark Server via TCP. We do require a VPN or a secure network, since the Spark Protocol is currently not yet encrypted.
Our second API extension point is intended for users that require adding functionality to our Spark Server. If you are interested in extending the server process through custom order types, market data sources, or execution gateways, please see the [Spark Server SDK](https://github.com/BlueTradingSystems/spark_sdk).
### In Depth
* [Interface Overview](doc/Overview.md)
* [Threading Notes](doc/Threading.md)
## Getting Started
### Git
* First clone the spark_client_sdk repo
@@ -11,7 +34,7 @@
```
## Build
### Build
* Use msbuild to target windows / .net 4.71
* Install studio here if you don't have it: https://visualstudio.microsoft.com/downloads/
* Use VSCode for editing, it's better: https://code.visualstudio.com/
@@ -24,7 +47,7 @@ spark_client_sdk\src\spark_sdk> msbuild
* spark_sdk binaries will be produced in the bin\Debug directory
## Connecting to Spark Server
### Connecting to Spark Server
* Start your exe using the -ConfigServer parameter to point at a running Spark Server
```
@@ -35,7 +58,7 @@ spark_client_sdk\src\spark_sdk> msbuild
include: "http://location:8000/config/"
```
## Examples
### Examples
* Make sure you can connect to a running server
* run spark_sdk.exe with no parameters to see help
```
@@ -58,22 +81,15 @@ Arguments:
* [Driver](src/spark_sdk/samples/SDKMain.cs)
## Excel
### Excel
```
spark_sdk\bin\Debug\net471> start spark_excel-addin64-packed.xll
```
* This will start excel and load the bts addin
* Check the [```excel```](excel/) directory for an example spreadsheet
## Notes
* Our client side API is based on Google's protocol buffers; the message types are all protos. https://developers.google.com/protocol-buffers/
* We extended the protoc compiler to generate c#, c++, excel and js bindings to the services provided by our server process (https://github.com/BlueTradingSystems/spark_sdk)
* ### Dotnet core
### Dotnet core
* Right now we only support c# Windows 10 clients, but the package targets both net471 and .net core 2.1.6, so in theory one could run a .net core or c++ client on linux with a little work.
+103
View File
@@ -0,0 +1,103 @@
## Spark Client SDK Overview
The high level description of our order entry interface is as follows:
```
service OrderService {
// RPCs
rpc create_order(Create) returns (Response)
rpc cancel_order(Cancel) returns (Response)
rpc update_order(Update) returns (Response)
// Streams
rpc orders (OrdersSub) returns (stream OrderRecord);
rpc fills (FillsSub) returns (stream Fill);
}
```
This description uses the Google Protocol Buffers syntax to define the server interface (we use our own little compiler to generate bindings to this interface in C#, C++ and Excel). Using this server interface we can create, cancel or update orders, using the Remote Procedure Calls (RPCs) defined these orders can be exchange native orders or our own high level algo orders, or new order types created by users via the Spark Server SDK). We can monitor order state by subscribing to the orders stream above, which produces a a stream of OrderRecord objects, each capturing the latest state of a particular order, as it goes through it life cycle.
An OrderRecord looks like this:
```
message OrderRecord {
uint32 key;
uint32 parent_key;
OrderDefinition def;
OrderState state;
}
```
We have an order key, a possibly null parent order key, an OrderDefinition record, which defines the basic elements of the order, namely its type, side, security, account, etc, and an OrderState record, which captures the latest state of the order:
```
message OrderState {
// Standard order state, shared by all order types
OrderStatus status ;
double price ;
uint32 quantity ;
uint32 filled_quantity;
double last_price;
double avg_price;
string last_msg;
google.protobuf.Timestamp created;
google.protobuf.Timestamp last_change;
// Custom order state, specific to the order type in question
oneof custom {
// native order types
MarketOrderState market;
LimitOrderState limit;
StopOrderState stop;
StopLimitOrderState stop_limit;
// algo order types
IcebergOrderState iceberg;
SpreaderOrderState spreader;
TimeBoxOrderState time_box;
TickOrderState tick;
LeanOrderState lean;
JoinOrderState join;
TopOrderState top;evident
TriggerOrderState trigger;
CoverOrderState cover;
OffsetOrderState offset;
DynamicOrderState dynamic;
}
}
```
This OrderState record consists of a common part, applicable to all order types, and a custom part that is specific to the particular order type the record is associated with. Most of the standard fields should be self-explanatory, the latest price, the latest quantity, the filled quantity, etc. The status enumerate field tells you which state the order is in. We currently define the following states:
```
enum OrderStatus {
// The order has been constructed but not acted on. Inactive orders
// can be abandoned without consequences. This state should only be
// used internally by the order manager, i.e. it should never appear
// in externally visible orders.
ORDER_STATUS_INACTIVE = 0;
// The order is currently working, i.e. its algorithm is operating.
ORDER_STATUS_WORKING = 1;
// The order has completed successfully and accomplished its
// goal. This is a terminal state.
ORDER_STATUS_COMPLETED = 2;
// The order was terminated orderly before it had a chance to
// complete. This is a terminal state.
ORDER_STATUS_CANCELED = 3;
// The order has encountered an unexpected condition from which it
// cannot recover. This a terminal state.
ORDER_STATUS_ERROR = 4;
// The last known state for this order was ORDER_STATUS_WORKING, but
// since then the execution gateway has signaled a disconnect. This
// is not a terminal state.
ORDER_STATUS_DISCONNECTED = 5;
// The order is initializiYou can ng. It cannot be modified at this
point.
ORDER_STATUS_PENDING_WORKING = 6;
// The order is invalid and was rejected by Spark (not the
// exchange), on creation. This is a terminal state.
ORDER_STATUS_REJECTED_BY_SPARK= 7;
}
```
### Threading
Check out our API Threading Doc [here](Threading.md).
+74
View File
@@ -0,0 +1,74 @@
# Client API Threading
BTS API provides two types of calls. There are RPC (remote procedure calls) which accept an argument and return a value and there are streams of tabular data which we call subscriptions. All communication to and from the server happens on a connection thread owned by the ServiceContext object and data must be marshaled back to the right context when the call is complete.
## RPC
### C#
All API calls provide both a synchronous and [asynchronous](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/async) version. If you are calling the API from a WPF or Windows Forms application you should always prefer the async version of the method because it will efficiently make the call and resume execution on the correct thread without blocking or lagging user interactions. The synchronous calls are intended for use in console applications where nothing else needs use of the thread until the data is available.
The async version of the method will return a `Result<T>` type which is used to signal if an error occurred during the call. You should test the Result.success to see if the call succeeded before using Result.value.
```csharp
var s = context.locate<api.user.AuthService>();
var result = await s.get_users_async(new GetUsersRequest());
if (result.success) {
Console.WriteLine(result.value);
}
else {
Console.WriteLine($"Error {result.error_message}");
}
```
### C++
All C++ API calls also provide both a blocking synchronous version and a callback based asynchronous version. In the asynchronous case the callback will execute on the ServiceContext thread and you will need to handle marshaling that data to the appropriate thread. Just like in c# the callback will receive a `Result<T>` which will indicate success or failure. `Result.value` returns an `std::shared_ptr` so you have control over the lifetime of the value.
## Subscriptions
BTS provides streaming updates for some types of data. These updates are incremental in nature and will provide a snapshot of the current state on a new subscription. Streaming updates use the [ReactiveX library](http://reactivex.io) to manage subscribing and unsubscribing. This library provides a rich set of operators that you can use to slide and dice the data streams based on your specific application requirements.
### C#
The subscription callback will arrive on the ServiceContext thread but it can be easily marshaled to the thread of your choice using the [ObserveOn](http://reactivex.io/documentation/operators/observeon.html) operator. For a WPF or Windows Forms application the most common use of this will be [ObserveOnDispatcher]() which will simply execute the callback in the context of the original calling thread. By your choice of where to place the `ObserveOnDispatcher` call in your reactive call chain you can choose whether other operators execute before after switching threads.
In this example the `Where` and `SelectMany` operators will execute on `ServiceContext` connection thread and only the resulting matches will be marshaled across to the calling thread. It is safe to unsubscribe by disposing `sub` from any thread.
```csharp
var orders = context.locate<OrderService>();
ObservableCollection<OrderRecord> orders_with_errors;
IDisposable sub =
orders
.subscribe_orders()
.SelectMany(update => update.added)
.Where(o => o.State.Status == OrderStatus.Error)
.ObserveOnDispatcher()
.Subscribe(o => {
orders_with_errors.Add(o);
});
```
### C++
The C++ subscription callbacks use the [RxCpp](https://github.com/ReactiveX/RxCpp) library which implements the [ReactiveX](http://reactivex.io) operators. The subscribe call will return an `rxcpp::composite_subscription` which implements [RAII](https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization) and will unsubscribe when it is destroyed.
```cpp
#include "lib/api/public/ServiceContext.h"
#include "lib/api/services/OrderService.client.pb.h"
#include <rxcpp/rx.hpp>
#include <google/protobuf/util/json_util.h>
//...
bts::api::ServiceContext ctx;
auto client = ctx.locate<bts::api::orderman::OrderService>();
auto sub =
client.subscribe_orders().subscribe([=](const bts::api::orderman::OrdersUpdate& update) {
std::string result;
for(const auto& order : update.added()) {
auto status = google::protobuf::util::MessageToJsonString(*order, &result, {});
std::cout << "New order: " << result << std::endl;
}
});
```
+2 -1
View File
@@ -22,7 +22,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.4.0" />
<PackageReference Include="Google.Protobuf" Version="3.6.1" />
<PackageReference Include="System.Reactive" Version="3.1.1" />
<PackageReference Include="System.Reactive.PlatformServices" Version="3.1.1" />
<PackageReference Include="NUnit" Version="3.10.1" />
@@ -61,6 +61,7 @@
<None Include="$(OutputPath)\net471\spark_excel_example_2018.xlsm" pack="true" PackagePath=".\excel\spark_excel_example_2018.xlsm" />
<None Include="$(OutputPath)\net471\spark_excel-addin64-packed.xll" pack="true" PackagePath=".\excel\spark_excel-addin64-packed.xll" />
<None Include="$(OutputPath)\net471\spark_excel-addin64.dna" pack="true" PackagePath=".\excel\spark_excel-addin64.dna" />
<None Include="doc/**" pack="true" PackagePath=".\doc\" />
</ItemGroup>
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences" Condition= " '$(SparkRoot)' != '' ">
@@ -12,9 +12,10 @@ namespace bts.mcore
class SecurityTests {
[Test]
public void test_security_equal() {
SecurityImmutable a = new Security() { Id = 42 };
SecurityImmutable b = new Security() { Id = 42 };
SecurityImmutable c = new Security() { Id = 4 };
SecurityImmutable a = new SecurityImmutable(new Security() { Id = 42 });
SecurityImmutable b = new SecurityImmutable(new Security() { Id = 42 });
SecurityImmutable c = new SecurityImmutable(new Security() { Id = 4 });
Assert.IsTrue(a == b);
Assert.IsTrue(a.Equals(b));
@@ -25,9 +25,9 @@ namespace bts.tests {
parent_id = parent;
}
public char name { get; }
public char name { get; set; }
public int id { get; }
public int parent_id { get; }
public int parent_id { get; set; }
public override bool Equals(object obj) {
Order other = (Order)obj;
@@ -133,6 +133,9 @@ namespace bts.tests {
/// 2) Insert - all items are properly added via <see cref="SortedTree{T, TKey}.Insert(T)"/>
/// 3) Reset - all items are properly added via <see cref="SortedTree{T, TKey}.Reset(IEnumerable{T})"/>
/// 4) Replace - all items are properly updated with a new value and/or parent via <see cref="SortedTree{T, TKey}.TryReplace(TKey, Func{T, T})"/>
/// a) delegate returns new value
/// b) delegate mutates existing value
/// - failing to account for this usage led to a bug in the OrderBook ca. 12/20/2018 (https://bluetradesys.atlassian.net/browse/SPARK-1903)
// 1) Constructor Initialization
var tree_asc = new SortedTree<Order, int>(Order.name_asc, id, pid, input);
@@ -154,6 +157,7 @@ namespace bts.tests {
// 4) Replace
tree_asc.Reset(input);
tree_desc.Reset(input);
//// a) delegate returns new value
var modified_input = _randomize_values(input);
foreach (var v in modified_input) {
Assert.IsTrue(tree_asc.TryReplace(id(v), _ => v));
@@ -162,7 +166,31 @@ namespace bts.tests {
// verify asc/desc
assert_state_then_clear(tree_asc, modified_input, Order.name_asc);
assert_state_then_clear(tree_desc, modified_input, Order.name_desc);
// reset with modified_input since we are mutating next ('input' is essentially a global variable, shared across the test iterations).
tree_asc.Reset(modified_input);
tree_desc.Reset(modified_input);
//// b) delegate mutates existing value
for (int i = 0; i < modified_input.Count; i++) {
var a = modified_input[i];
var b = modified_input[modified_input.Count - i - 1];
var swap_name = _swap_name_del(b.name);
var swap_parent = _swap_parent_del(b.parent_id);
var swap_both = _swap_name_and_parent_del(b.name, b.parent_id);
var reset = _swap_name_and_parent_del(a.name, a.parent_id);
foreach (var tree in new[] { tree_asc, tree_desc }) {
Assert.IsTrue(tree.TryReplace(id(a), swap_name));
Assert.IsTrue(tree.TryReplace(id(a), swap_parent));
// reset 'a' so swap_both will actually change values (we already swapped name and parent individually above).
Assert.IsTrue(tree.TryReplace(id(a), reset));
Assert.IsTrue(tree.TryReplace(id(a), swap_both));
// reset 'a' to finish. Since tree_asc/desc share the same actual orders, this protects the other tree from becoming unsorted as a result of the mutations.
Assert.IsTrue(tree.TryReplace(id(a), reset));
}
}
// verify asc/desc
assert_state_then_clear(tree_asc, modified_input, Order.name_asc);
assert_state_then_clear(tree_desc, modified_input, Order.name_desc);
// local methods
void assert_state_then_clear(SortedTree<Order, int> tree, IEnumerable<Order> vals, IComparer<Order> comp) {
Assert.IsTrue(tree.SequenceEqual(_hierarchically_sorted_list(vals, comp)));
clear_action(tree);
@@ -265,6 +293,20 @@ namespace bts.tests {
return reshuffled;
}
Func<Order, Order> _swap_name_del(char name) => o => {
o.name = name;
return o;
};
Func<Order, Order> _swap_parent_del(int parent) => o => {
o.parent_id = parent;
return o;
};
Func<Order, Order> _swap_name_and_parent_del(char name, int parent) => o => {
o.name = name;
o.parent_id = parent;
return o;
};
void _write_tree_to_console(SortedTree<Order, int> tree) {
foreach (var str in _fmt_output(tree.RootNodes))
Console.WriteLine(str);
+289
View File
@@ -0,0 +1,289 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using bts.api;
using bts.api.admin;
using bts.api.core;
using bts.api.test;
using bts.test;
using bts.api.orderman;
using mbts;
using mbts.tests;
using bts.co2;
namespace bts.tests
{
[TestGroup(TestType = TestType.System)]
public class LimitsTests : IDisposable {
ServiceContext _context;
OrderService _order_service;
AdminService _admin_service;
public LimitsTests (){
_context = new ServiceContext();
_order_service = _context.locate<OrderService>();
_admin_service = _context.locate<AdminService>();
var auth = _context.login("bts","");
auth.Wait(3000);
}
public void Dispose() {
Disposable.dispose(ref _order_service);
Disposable.dispose(ref _admin_service);
Disposable.dispose(ref _context);
}
async Task<IEnumerable<SecurityImmutable>> all_futures(string symbol) {
var request = new MDRequest() {
Host = "system_test",
Channels = {
new SecurityChannel() {
Time = 0,
Flags = 0,
Type = SecurityType.Future,
Exchange = Venue.Sim,
Symbol = symbol,
TradeCursor = 0,
RfqCursor = 0
}
}
};
var relay = _context.locate<MarketDataRelay>();
await Task.Delay(100);
var result = await relay.requestmd_async(request);
List<SecurityImmutable> securities = new List<SecurityImmutable>();
if (result.success) {
foreach (var ch in result.value.Channels) {
foreach (var update in ch.Updates) {
if (update.Security != null) {
securities.Add(new SecurityImmutable(update.Security));
}
}
}
}
return securities;
}
[Test]
public async Task test_clip_limits() {
//Get and set limit values from the admin service
uint test_limit_value = 10u;
string test_symbol = "CL";
var test_user = (name: "bts", id: 1u);
var test_account = (name: "ACC A", id: 1u);
var account_data = await AdminUtilities.get_account_data(_admin_service, test_account.name);
Assert.IsTrue(account_data.HasValue);
var old_clip_limit = AdminUtilities.get_clip_limit(account_data, test_symbol);
//create Orders Here
var all = await all_futures(test_symbol);
SecurityImmutable? sec = all.FirstOrDefault();
Assert.IsTrue(sec.HasValue);
uint under_limit_order_key;
uint over_limit_order_key;
uint no_limit_order_key;
var order_def = create_order_def(sec.Value.Id, Side.Buy, test_account, test_user);
Assert.IsTrue(sec.HasValue, "Unable to create order without security");
await AdminUtilities.remove_clip_limit(_admin_service, test_account.name, test_symbol);
Result<Response> no_limit_order_result = await _order_service.create_order_async(new Create() {
NewOrder = order_def,
Price = 5,
Quantity = test_limit_value
});
var set_success = await AdminUtilities.set_clip_limit(_admin_service, test_limit_value, account_data, test_symbol);
Assert.IsTrue(set_success, "Failed to set limit");
Result<Response> under_limit_order_result = await _order_service.create_order_async(new Create() {
NewOrder = order_def,
Price = 5,
Quantity = test_limit_value
});
Result<Response> over_limit_order_result = await _order_service.create_order_async(new Create() {
NewOrder = order_def,
Price = 5,
Quantity = test_limit_value + 1
});
under_limit_order_key = under_limit_order_result.value.OrderKey;
over_limit_order_key = over_limit_order_result.value.OrderKey;
no_limit_order_key = no_limit_order_result.value.OrderKey;
bool waiting_for_orders = true;
var orders = _order_service.subscribei_orders().Subscribe(ords =>
{
waiting_for_orders = false;
IEnumerable<OrderRecordImmutable> filtered_orders = ords.all.Where(x => x.Key == under_limit_order_key || x.Key == over_limit_order_key || x.Key == no_limit_order_key);
Assert.IsTrue(filtered_orders.Count() == 3, "There should be 3 matching orders... there are not");
foreach(var o in filtered_orders)
{
if(o.Key == under_limit_order_key) {
Assert.IsTrue(o.State.Status == OrderStatus.Working, "Under Limit Order is not 'Working'");
}
else if(o.Key == over_limit_order_key) {
Assert.IsTrue(o.State.Status == OrderStatus.RejectedBySpark, "Over Limit Order is not 'RejectedBySpark'");
}
else if(o.Key == no_limit_order_key) {
Assert.IsTrue(o.State.Status == OrderStatus.RejectedBySpark, "No Limit Order is not 'RejectedBySpark'");
}
}
});
while(waiting_for_orders) {
await Task.Delay(100);
}
// Restore the Limits to the original values
bool success = false;
if(old_clip_limit.HasValue) {
success = await AdminUtilities.set_clip_limit(_admin_service, old_clip_limit.Value, test_account.name, test_symbol);
}
else {
success = await AdminUtilities.remove_clip_limit(_admin_service, test_account.name, test_symbol);
}
Assert.IsTrue(success, "Failed to restore Limit");
}
public OrderDefinition create_order_def(uint security_id, Side side, (String name, uint id) account, (String name, uint id) user){
return new OrderDefinition {
SecurityKey = security_id,
Side = Side.Buy,
TimeInForce = TimeInForce.Day,
CustomDef = new CustomOrderDefinition { Limit = new LimitOrderDefinition { } },
CtiCode = CTICode.CtiCode1,
CustomerOrFirm = CustomerOrFirm.Firm,
ManualOrderIndicator = ManualOrderIndicator.Yes,
Account = account.name,
AccountId = account.id,
User = user.name,
UserId = user.id
};
}
}
public class AdminUtilities {
public static async Task<BTSAccountImmutable?> get_account_data (AdminService admin_service, string account_name)
{
Update<AdminDataImmutable, int> update = await admin_service.subscribei_admin_data().FirstAsync();
foreach (var acc in update.all.First().Accounts) {
if(acc.Name == account_name) {
return acc;
}
}
return null;
}
public static AccountSecurityClipLimitUnitImmutable? get_clip_limit_row(BTSAccountImmutable? account_data, string symbol, SecurityType security_type = SecurityType.Future, Venue venue = Venue.Sim) {
IEnumerable<AccountSecurityClipLimitUnitImmutable> clip_limit_rows = account_data.Value.SecurityClipLimits.Limit.Where(
r => r.Security.SecuritySymbol == symbol
&& r.Security.Exchange == venue
&& r.Security.SecurityType == security_type);
return clip_limit_rows.Any() ? clip_limit_rows.First() : (AccountSecurityClipLimitUnitImmutable?) null;
}
public static uint? get_clip_limit(BTSAccountImmutable? account_data, string symbol, SecurityType security_type = SecurityType.Future, Venue venue = Venue.Sim) {
var row = get_clip_limit_row(account_data,symbol,security_type,venue);
return row.HasValue ? row.Value.ClipSize : (uint?) null;
}
public static async Task<uint?> get_clip_limit(AdminService admin_service, string account_name, string symbol, SecurityType security_type = SecurityType.Future, Venue venue = Venue.Sim) {
var account_data = await get_account_data(admin_service, account_name);
return get_clip_limit(account_data, symbol, security_type, venue);
}
public static async Task<bool> set_clip_limit(AdminService admin_service, uint clip_value, string account_name, string symbol, SecurityType security_type = SecurityType.Future, Venue venue = Venue.Sim) {
var account_data = await get_account_data(admin_service, account_name);
return await set_clip_limit(admin_service, clip_value,account_data, symbol,security_type, venue);
}
public static async Task<bool> set_clip_limit(AdminService admin_service, uint clip_value, BTSAccountImmutable? account_data, string symbol, SecurityType security_type = SecurityType.Future, Venue venue = Venue.Sim) {
AccountSecurityClipLimitUnitImmutable? origin_clip_limit_row = get_clip_limit_row(account_data,symbol,security_type,venue);
AccountSecurityClipLimitUnitImmutable new_clip_limit_row;
List<AccountSecurityClipLimitUnitImmutable> clip_limits_list = account_data.Value.SecurityClipLimits.Limit.ToList();
if(origin_clip_limit_row.HasValue) {
clip_limits_list.Remove(origin_clip_limit_row.Value);
}
new_clip_limit_row = (AccountSecurityClipLimitUnitImmutable) new AccountSecurityClipLimitUnit {
Security = new SecurityScope(){ SecuritySymbol = symbol, Exchange = venue, SecurityType = security_type },
ClipSize = clip_value
};
clip_limits_list.Add(new_clip_limit_row);
AccountSecurityClipLimits temp_scl = new AccountSecurityClipLimits();
temp_scl.Limit.AddRange(clip_limits_list.Select(x => x.CloneToMutable()));
var new_account_data = account_data.Value.with(security_clip_limits: temp_scl);
var update_ret = await admin_service.update_account_async(new AccountUpdateAPIArgument {
CompleteData = new_account_data.CloneToMutable()
});
return update_ret.success;
}
public static async Task<bool> remove_clip_limit(AdminService admin_service, string account_name, string symbol, SecurityType security_type = SecurityType.Future, Venue venue = Venue.Sim) {
var account_data = await get_account_data(admin_service, account_name);
return await remove_clip_limit(admin_service, account_data, symbol, security_type, venue);
}
public static async Task<bool> remove_clip_limit(AdminService admin_service, BTSAccountImmutable? account_data, string symbol, SecurityType security_type = SecurityType.Future, Venue venue = Venue.Sim) {
AccountSecurityClipLimitUnitImmutable? origin_clip_limit_row = get_clip_limit_row(account_data,symbol,security_type,venue);
List<AccountSecurityClipLimitUnitImmutable> clip_limits_list = account_data.Value.SecurityClipLimits.Limit.ToList();
if(origin_clip_limit_row.HasValue) {
clip_limits_list.Remove(origin_clip_limit_row.Value);
AccountSecurityClipLimits temp_scl = new AccountSecurityClipLimits();
temp_scl.Limit.AddRange(clip_limits_list.Select(x => x.CloneToMutable()));
var new_account_data = account_data.Value.with(security_clip_limits: temp_scl);
var update_ret = await admin_service.update_account_async(new AccountUpdateAPIArgument {
CompleteData = new_account_data.CloneToMutable()
});
return update_ret.success;
}
else
{
return false;
}
}
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net471</TargetFramework>
<TargetFramework>netstandard2.0</TargetFramework>
<Platform>x64</Platform>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
+9 -4
View File
@@ -15,12 +15,17 @@ namespace sparkcmd {
uint _parallel = 1;
bool _list;
TestType test_type = TestType.Unit;
public TestCommand() {
IsCommand("test", "Run managed unit tests");
// i comes thorugh as "t" which seems daft.
// i comes thorugh as "t" which seems daft.
HasOption("t|timeout", "Timeout unit tests", i => _timeout = 10);
HasOption<uint>("n|parallel", "How many tests to run in parallel", i => _parallel = i);
HasOption("l|list", "List all tests", _ => _list = true);
HasOption("unit","Run unit tests", _ => test_type = TestType.Unit);
HasOption("system","Run system tests", _ => test_type = TestType.System);
HasOption("shell","Run shell tests", _ => test_type = TestType.Shell);
HasAdditionalArguments(null, " [Test List]");
}
@@ -35,7 +40,7 @@ namespace sparkcmd {
if (_timeout == 0 && tests.Length == 1) {
//System.Threading.Thread.Sleep(5000);
using (var trr = new TestResultReceiver(true)) {
InProcessTestRunner.run_test_syncronously(tests[0], Enumerator, trr.get_reporter());
InProcessTestRunner.run_test_synchronously(tests[0], Enumerator, trr.get_reporter());
trr.print_summary();
return trr.ErrorCount;
}
@@ -44,7 +49,7 @@ namespace sparkcmd {
return run_tests(Enumerator.match(tests).Select(t => t.name));
}
else {
return run_tests(Enumerator.Tests.Select(t => t.full_name));
return run_tests(Enumerator.get_of_type(test_type).Select(t => t.full_name));
}
}
@@ -59,7 +64,7 @@ namespace sparkcmd {
void list_tests() {
Console.WriteLine("All tests: ");
foreach (var t in Enumerator.TestGroups) {
foreach (var t in Enumerator.get_groups_of_type(test_type)) {
ConsoleEx.WriteLine(t.name, ConsoleColor.Green);
foreach (var test in t.methods) {
Console.Write($" {test.name}");
+3 -3
View File
@@ -8,10 +8,10 @@ using System.Linq;
namespace sparkcmd {
class Program {
static void Main(string[] args) {
static int Main(string[] args) {
mbts.config.Configuration.initialize();
var commands = ConsoleCommandDispatcher.FindCommandsInSameAssemblyAs(typeof(Program));
ConsoleCommandDispatcher.DispatchCommand(commands, args, Console.Out);
return;
return ConsoleCommandDispatcher.DispatchCommand(commands, args, Console.Out);
}
}
}
+2 -3
View File
@@ -2,8 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net471</TargetFramework>
<!--<TargetFrameworks>net471;netcoreapp2.1</TargetFrameworks>-->
<TargetFrameworks>net471;netcoreapp2.1</TargetFrameworks>
<RuntimeIdentifiers>win7-x64;ubuntu.16.04-x64</RuntimeIdentifiers>
<Authors>Blue Trading Systems</Authors>
<Company>Blue Trading Systems</Company>
@@ -18,7 +17,7 @@
<ProjectReference Include="../spark_api/spark_api.csproj" />
<!--<ProjectReference Include="..\spark\Spark.csproj" />-->
<ProjectReference Include="..\spark_core\spark_core.csproj" />
<ProjectReference Include="..\spark_test\spark_test.csproj" Condition="'$(Configuration)'=='Debug'" />
<ProjectReference Include="..\spark_test\spark_test.csproj" />
<!--<Proto3 Include="**/*.proto" />-->
</ItemGroup>
+6
View File
@@ -3,3 +3,9 @@
rm -rf $1
mkdir $1
cp -r $2/files/* $1
for filename in $1/*; do
if [[ $filename == *.xz ]]; then
unxz $filename
fi
done
Binary file not shown.
+240 -105
View File
@@ -1,3 +1,6 @@
/* -------------------------------------------------------------------------------- */
/* Main tables */
/* -------------------------------------------------------------------------------- */
create table if not exists
session (
version TEXT,
@@ -5,6 +8,7 @@ session (
build_type TEXT,
session_start TIMESTAMP PRIMARY KEY
);
create index if not exists session_idx on session(session_start);
create table if not exists
trace (
@@ -20,55 +24,46 @@ trace (
sn INTEGER,
uint32_1 INTEGER
);
drop view if exists recent_trace;
create view recent_trace as
select * from trace order by rowid desc limit 140123;
create index if not exists trace_idx on trace(session_start,channel,sn,ts);
create index if not exists trace_t_idx on trace(session_start,ts);
drop view if exists ordered_trace;
create view ordered_trace as
select
recent_trace.*,
row_number() over (order by session_start,ts) entry_rank
from
recent_trace;
/* -------------------------------------------------------------------------------- */
/* Main Views */
/* -------------------------------------------------------------------------------- */
drop view if exists delta_trace;
create view delta_trace as
/* An ordered view of the traces, with extra columns for the delta
betwen consecutive traces as well as the delta between related
(scoped) traces */
drop view if exists log_view;
create view log_view as
select
current.*,
(current.ts - previous.ts) / 1000.0 delta
from
ordered_trace current,
ordered_trace previous
where
current.entry_rank = previous.entry_rank+1;
drop view if exists log;
create view log as
select
delta_trace.*,
trace.*,
trace.rowid entry_id,
(ts-lag(ts) over by_session_ts)/1000.0 delta,
case cor_event>0 when 1 then (ts-cor_event)/1000.0 else 0 end scope_delta,
case cor_event>0 when 1 then "end of " || entry_kind else entry_kind end scoped_entry
from
delta_trace;
drop view if exists events;
create view events as
trace
window
by_session_ts as (order by session_start,ts);
/* A view identifying each high level event (requote or hedge) and
annotating it with its latency */
drop view if exists event_view;
create view event_view as
select
fix_reads.session_start,
"hedge" event_type,
fix_reads.hts hts_start,
fix_reads.entry_id event_id,
fix_reads.ts start,
fix_writes.ts stop,
(fix_writes.ts - fix_reads.ts) / 1000.0 duration,
row_number() over (order by fix_reads.session_start,fix_reads.ts,fix_writes.ts) event_rank ,
fix_reads.channel,
fix_reads.sn
from
(select session_start, channel, sn, ts from recent_trace where entry_kind='fix_msg_r') fix_reads,
(select session_start, channel, sn, ts from recent_trace where entry_kind='before_fix_socket_w') fix_writes
(select session_start, channel, sn, hts,ts,rowid entry_id from trace where entry_kind='fix_msg_r' order by ts) fix_reads,
(select session_start, channel, sn, hts,ts,rowid entry_id from trace where entry_kind='before_fix_socket_w') fix_writes
where
fix_reads.session_start = fix_writes.session_start and
fix_reads.channel = fix_writes.channel and
@@ -77,35 +72,168 @@ union
select
md_reads.session_start,
"requote" event_type,
md_reads.hts hts_start,
md_reads.rowid event_id,
md_reads.ts start,
fix_writes.ts stop,
(fix_writes.ts - md_reads.ts) / 1000.0 duration,
row_number() over (order by md_reads.session_start,md_reads.ts,fix_writes.ts) event_rank ,
md_reads.channel,
md_reads.sn
from
(select session_start, channel, sn, ts from recent_trace where entry_kind='md') md_reads,
(select session_start, channel, sn, ts from recent_trace where entry_kind='before_fix_socket_w') fix_writes
(select distinct session_start, channel, sn, hts,ts from trace where entry_kind='md' order by ts) md_reads,
(select session_start, channel, sn, hts,ts,rowid entry_id from trace where entry_kind='before_fix_socket_w') fix_writes
where
md_reads.session_start = fix_writes.session_start and
md_reads.channel = fix_writes.channel and
md_reads.sn = fix_writes.sn;
drop view if exists event_log;
create view event_log as
/* A view on hedge events, identifying each order sent as part of the event*/
drop view if exists hedge_trace_view;
create view hedge_trace_view as
select
log.*,
event_type,
event_rank,
events.duration event_duration,
events.start event_start,
events.stop event_stop
session.version,
session.host,
session.build_type,
session.session_start,
trace.hts trace_time,
uint64_1 order_key,
duration total,
event_id
from
log,
events
event_view,
trace,
session
where
log.session_start = events.session_start and
log.ts >= events.start and log.ts <= events.stop;
session.session_start = trace.session_start and
session.session_start = event_view.session_start and
event_view.channel=trace.channel and event_view.sn=trace.sn and
event_type='hedge' and
entry_kind='NativeOrder::on_activate' and
cor_event=0;
/* A view on requote events, identifying each order sent as part of the event*/
drop view if exists requote_trace_view;
create view requote_trace_view as
select
session.version,
session.host,
session.build_type,
session.session_start,
trace.hts trace_time,
uint64_1 order_key,
duration total,
event_id
from
event_view,
trace,
session
where
session.session_start = trace.session_start and
session.session_start = event_view.session_start and
event_view.channel=trace.channel and event_view.sn=trace.sn and
event_type='requote' and
entry_kind='NativeOrder::on_update' and
cor_event=0;
/* -------------------------------------------------------------------------------- */
/* Archive tables/view */
/* -------------------------------------------------------------------------------- */
/* Auxiliary tables and views, used to archive the results of the main
views to speed up analysis as data accumulates */
create table if not exists
event_archive (
session_start TIMESTAMP,
event_type TEXT,
hts_start TIMESTAMP,
event_id INTEGER,
start INTEGER,
stop INTEGER,
duration float,
channel TEXT,
sn INTEGER
);
create index if not exists event_archive_idx on event_archive(session_start,start,stop);
create table if not exists
log_archive(
session_start TIMESTAMP,
ts INTEGER,
hts timestamp,
channel TEXT,
entry_kind TEXT,
txt_1 TEXT,
uint64_1 INTEGER,
thread TEXT,
cor_event INTEGER,
sn INTEGER,
uint32_1 INTEGER,
entry_id INTEGER,
delta float,
scope_delta float,
scoped_entry TEXT
);
create index if not exists log_archive_idx on log_archive(session_start,ts);
create table if not exists
hedge_trace_archive (
version TEXT,
host TEXT,
build_type TEXT,
session_start TIMESTAMP,
trace_time TIMESTAMP,
order_key INTEGER,
total float,
event_id integer
);
drop view if exists hedge_trace;
create view hedge_trace as
select * from hedge_trace_view union select * from hedge_trace_archive;
create table if not exists
requote_trace_archive (
version TEXT,
host TEXT,
build_type TEXT,
session_start TIMESTAMP,
trace_time TIMESTAMP,
order_key INTEGER,
total float,
event_id integer
);
drop view if exists requote_trace;
create view requote_trace as
select * from requote_trace_view union select * from requote_trace_archive;
/* a synthetis of the log and events, focusing only on traces that are
part of hedge/requote events */
create table if not exists
event_log_archive (
session_start TIMESTAMP,
ts INTEGER,
hts timestamp,
channel TEXT,
entry_kind TEXT,
txt_1 TEXT,
uint64_1 INTEGER,
thread TEXT,
cor_event INTEGER,
sn INTEGER,
uint32_1 INTEGER,
entry_id INTEGER,
delta float,
scope_delta float,
scoped_entry TEXT,
event_type TEXT,
event_id INTEGER,
event_duration float,
hts_start TIMESTAMP,
event_start INTEGER,
event_stop INTEGER
);
create index if not exists event_log_archive_idx on event_log_archive(session_start);
drop view if exists pretty_log;
create view pretty_log as
@@ -115,69 +243,76 @@ select
scope_delta ,
event_duration,
event_type,
event_rank,
event_id,
hts,
ts,
session_start,
entry_rank
entry_id
from
event_log;
event_log_archive;
drop view if exists last_pretty_log;
create view last_pretty_log as
select * from pretty_log where session_start=(select max(session_start) from session);
select
*
from
pretty_log
where
session_start=(select max(session_start) from session);
-- drop view if exists summary;
-- create view summary as
-- select session_start,event_type,count(*) count, avg(duration) avg, max(duration) max, min(duration) min, median(duration) median, stdev(duration) stdev from events group by session_start,event_type;
/*
drop view if exists event_stats;
create view event_stats as
select
session_start,
event_type,
count(*) count,
avg(duration) avg,
max(duration) max,
min(duration) min,
median(duration) median,
stdev(duration) stdev
from
event_archive
group by
session_start,
event_type;
*/
drop view if exists event_log_aux;
create view event_log_aux as
select
log_archive.*,
event_type,
event_id,
event_archive.duration event_duration,
event_archive.hts_start hts_start,
event_archive.start event_start,
event_archive.stop event_stop
from
log_archive,
event_archive
where
log_archive.session_start = event_archive.session_start and
log_archive.ts >= event_archive.start and log_archive.ts <= event_archive.stop;
begin transaction;
insert into hedge_trace_archive select * from hedge_trace_view;
insert into requote_trace_archive select * from requote_trace_view;
insert into event_archive select * from event_view;
insert into log_archive select * from log_view;
insert into event_log_archive select * from event_log_aux;
delete from trace;
delete from event_log_archive where
rowid in (select rowid from event_log_archive order by rowid desc limit -1 offset 10000123);
delete from hedge_trace_archive where
rowid in (select rowid from hedge_trace_archive order by rowid desc limit -1 offset 10000123);
delete from requote_trace_archive where
rowid in (select rowid from requote_trace_archive order by rowid desc limit -1 offset 10000123);
delete from log_archive where
rowid in (select rowid from log_archive order by rowid desc limit -1 offset 10000123);
delete from event_log_archive where
rowid in (select rowid from event_log_archive order by rowid desc limit -1 offset 10000123);
commit;
drop view if exists hedge_trace;
create view hedge_trace as
select
session.version,
session.host,
session.build_type,
session.session_start,
recent_trace.hts trace_time,
recent_trace.uint64_1 order_key,
hedge_events.duration total,
hedge_events.event_rank rank
from
recent_trace,
(select * from events where event_type='hedge') hedge_events,
session
where
entry_kind='NativeOrder::on_activate' and
recent_trace.cor_event = 0 and
recent_trace.channel = hedge_events.channel and
recent_trace.session_start = hedge_events.session_start and
recent_trace.sn = hedge_events.sn and
recent_trace.session_start = session.session_start;
drop view if exists requote_trace;
create view requote_trace as
select
session.version,
session.host,
session.build_type,
session.session_start,
recent_trace.hts trace_time,
recent_trace.uint64_1 order_key,
requote_events.duration total,
requote_events.event_rank rank
from
recent_trace,
(select * from events where event_type='requote') requote_events,
session
where
entry_kind='NativeOrder::on_update' and
recent_trace.cor_event = 0 and
recent_trace.channel = requote_events.channel and
recent_trace.session_start = requote_events.session_start and
recent_trace.sn = requote_events.sn and
recent_trace.session_start = session.session_start ;
delete from trace where
rowid in (select rowid from trace order by rowid desc limit -1 offset 10000123);
+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/AuthService.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/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/Symbols.conf;config/defaults/cme_reference_data.conf;config/defaults/edge.conf;config/defaults/jetfix.conf;config/defaults/logging.conf;config/defaults/orderman_cfg.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/threads.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/ExchangeSimCfg.proto;config/protos/MarketData.proto;config/protos/Ports.proto;config/protos/Symbols.proto;config/protos/UI.proto;config/protos/cme_reference_data.proto;config/protos/jetfix.proto;config/protos/logging.proto;config/protos/mercury_cfg.proto;config/protos/orderman_cfg.proto;config/protos/orders_fills_cleanup.proto;config/protos/perflog_cfg.proto;config/protos/quickbus_cfg.proto;config/protos/spreader.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/threads.proto;config/protos/toggles.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;jetfix/codec/FIXArray.cpp;jetfix/common/OutFIX.cpp;jetfix/connection/AsyncReader.cpp;jetfix/connection/IConnection.cpp;jetfix/connection/SocketConnection.cpp;jetfix/gateway/CoreGateway.cpp;jetfix/gateway/JetFIXGateway.cpp;jetfix/gateway/Session.cpp;jetfix/store/FIXFileStore.cpp;jetfix/store/session_name.cpp;jetfix/tests/async_reader_tests.cpp;jetfix/tests/decoding_tests.cpp;jetfix/tests/fix_encoding_stream_tests.cpp;jetfix/tests/fix_fragment_tests.cpp;jetfix/tests/jetfix_performance_tests.cpp;jetfix/tests/sample_fix.cpp;jetfix/tests/store_tests.cpp;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/Diag/MDPeriodicDumper.cpp;md/Diag/ShmDumper.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MDRecoverableConsumer.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/md2_tests.cpp;md/test/synthetic_book_merge_tests.cpp;mercury/actors/IPollableActor.cpp;mercury/broker/Broker.cpp;mercury/broker/BrokerProxy.cpp;mercury/broker/ILocalBroker.cpp;mercury/broker/IRemoteBroker.cpp;mercury/common/mercury_common.cpp;mercury/events/TimerEvent.cpp;mercury/executor/Executor.cpp;mercury/topics/Topic.cpp;metrics/metrics.cpp;metrics/system_metrics.cpp;orderman/actors/AsyncFactory.cpp;orderman/actors/ExecutionGateway.cpp;orderman/actors/FillStore.cpp;orderman/actors/MDSupplementarySource.cpp;orderman/actors/OrderStore.cpp;orderman/actors/SODPosition.cpp;orderman/actors/SecuritySrc.cpp;orderman/actors/ServiceBridge.cpp;orderman/actors/order_manager/OrderBuilder.cpp;orderman/actors/order_manager/OrderManager.cpp;orderman/actors/order_manager/OrderServicesData.cpp;orderman/events/CancelRejectEvent.cpp;orderman/events/NewExecutionReportEvent.cpp;orderman/limiter/LimitStore.cpp;orderman/limiter/Limiter.cpp;orderman/limiter/ProductLimitNode.cpp;orderman/limiter/ProductLimitTree.cpp;orderman/limiter/SecurityLimitNode.cpp;orderman/limiter/SecurityLimitTree.cpp;orderman/limiter/tests/limit_tests.cpp;orderman/order_factory/DynaLine 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/AuthService.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/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/Symbols.conf;config/defaults/cme_reference_data.conf;config/defaults/edge.conf;config/defaults/jetfix.conf;config/defaults/logging.conf;config/defaults/orderman_cfg.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/threads.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/ExchangeSimCfg.proto;config/protos/MarketData.proto;config/protos/Ports.proto;config/protos/Symbols.proto;config/protos/UI.proto;config/protos/cme_reference_data.proto;config/protos/jetfix.proto;config/protos/logging.proto;config/protos/mercury_cfg.proto;config/protos/orderman_cfg.proto;config/protos/orders_fills_cleanup.proto;config/protos/perflog_cfg.proto;config/protos/quickbus_cfg.proto;config/protos/spreader.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/threads.proto;config/protos/toggles.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/Diag/MDPeriodicDumper.cpp;md/Diag/ShmDumper.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MDRecoverableConsumer.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/md2_tests.cpp;md/test/synthetic_book_merge_tests.cpp;os/os.cpp;os/tests/os_tests.cpp;quickbus/core/LocalNode.cpp;quickbus/core/Quickbus.cpp;quickbus/core/SubscriptionID.cpp;quickbus/core/TableID.cpp;quickbus/message_model/Update.cpp;quickbus/message_model/merge_updates.cpp;quickbus/network/QBConnection.cpp;quickbus/network/QBConnectionManager.cpp;quickbus/network/endpoint_description.cpp;quickbus/network/quickbus_msgs.proto;quickbus/pubsub/TablePublisher.cpp;quickbus/pubsub/TableSubscriber.cpp;quickbus/pubsub/tests/qb_pubsub_tests.cpp;quickbus/routing/INode.cpp;quickbus/routing/NodeID.cpp;quickbus/routing/Router.cpp;quickbus/rpc/RPCClient.cpp;quickbus/rpc/RPCServer.cpp;quickbus/rpc/RPCSessionID.cpp;quickbus/rpc/rpc_utils.cpp;quickbus/rpc/tests/qb_rpc_tests.cpp;quickbus/tests/quickbus_tests.cpp;sparkproto/SparkProtos.proto;testing/catch_test_runner.cpp;utils/AuthToken.cpp;utils/Dispatcher.cpp;utils/GrowableSPSCQueue.cpp;utils/HTTPStream.cpp;utils/PBUtils.cpp;utils/Puid.cpp;utils/SecureLogon.cpp;utils/SharedMemory.cpp;utils/Sqlite_utils.cpp;utils/Uuid.cpp;utils/datetime.cpp;utils/download.cpp;utils/file_utils.cpp;utils/init_spark_lib.cpp;utils/is_unittest_environment.cpp;utils/stats.cpp;utils/tests/AuthTokenTests.cpp;utils/thread_manager.cpp)
+1
View File
@@ -0,0 +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/AuthService.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/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/Symbols.conf;config/defaults/cme_reference_data.conf;config/defaults/edge.conf;config/defaults/jetfix.conf;config/defaults/logging.conf;config/defaults/orderman_cfg.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/threads.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/ExchangeSimCfg.proto;config/protos/MarketData.proto;config/protos/Ports.proto;config/protos/Symbols.proto;config/protos/UI.proto;config/protos/cme_reference_data.proto;config/protos/jetfix.proto;config/protos/logging.proto;config/protos/mercury_cfg.proto;config/protos/orderman_cfg.proto;config/protos/orders_fills_cleanup.proto;config/protos/perflog_cfg.proto;config/protos/quickbus_cfg.proto;config/protos/spreader.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/threads.proto;config/protos/toggles.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/Diag/MDPeriodicDumper.cpp;md/Diag/ShmDumper.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MDRecoverableConsumer.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/md2_tests.cpp;md/test/synthetic_book_merge_tests.cpp;os/os.cpp;os/tests/os_tests.cpp;quickbus/core/LocalNode.cpp;quickbus/core/Quickbus.cpp;quickbus/core/SubscriptionID.cpp;quickbus/core/TableID.cpp;quickbus/message_model/Update.cpp;quickbus/message_model/merge_updates.cpp;quickbus/network/QBConnection.cpp;quickbus/network/QBConnectionManager.cpp;quickbus/network/endpoint_description.cpp;quickbus/network/quickbus_msgs.proto;quickbus/pubsub/TablePublisher.cpp;quickbus/pubsub/TableSubscriber.cpp;quickbus/pubsub/tests/qb_pubsub_tests.cpp;quickbus/routing/INode.cpp;quickbus/routing/NodeID.cpp;quickbus/routing/Router.cpp;quickbus/rpc/RPCClient.cpp;quickbus/rpc/RPCServer.cpp;quickbus/rpc/RPCSessionID.cpp;quickbus/rpc/rpc_utils.cpp;quickbus/rpc/tests/qb_rpc_tests.cpp;quickbus/tests/quickbus_tests.cpp;sparkproto/SparkProtos.proto;testing/catch_test_runner.cpp;utils/AuthToken.cpp;utils/Dispatcher.cpp;utils/GrowableSPSCQueue.cpp;utils/HTTPStream.cpp;utils/PBUtils.cpp;utils/Puid.cpp;utils/SecureLogon.cpp;utils/SharedMemory.cpp;utils/Sqlite_utils.cpp;utils/Uuid.cpp;utils/datetime.cpp;utils/download.cpp;utils/file_utils.cpp;utils/init_spark_lib.cpp;utils/is_unittest_environment.cpp;utils/stats.cpp;utils/tests/AuthTokenTests.cpp;utils/thread_manager.cpp)
+1 -1
View File
@@ -141,4 +141,4 @@ if (WIN32)
include(${CMAKE_SOURCE_DIR}/tools/vs_filters.cmake)
endif()
@@ -31,8 +31,9 @@ namespace {{package}} {
public {{name}} CloneToMutable() { return _impl.Clone(); }
// Implicit conversion operator
public static implicit operator {{name}}Immutable({{name}} other) {
return new {{name}}Immutable(other, false);
public static implicit operator Nullable<{{name}}Immutable>({{name}} other) {
if (other == null) return null;
else return new {{name}}Immutable(other, false);
}
public override bool Equals(object other) {
+17
View File
@@ -73,6 +73,8 @@ message CustomOrderDefinition
TriggerOrderDefinition trigger = 22;
CoverOrderDefinition cover = 23;
OffsetOrderDefinition offset = 24;
OCOOrderDefinition oco = 25;
PricerOrderDefinition pricer = 26;
DynamicOrderDefinition dynamic = 1000;
}
@@ -154,6 +156,17 @@ message OffsetOrderDefinition {
uint32 tick_offset_on_deploy = 1;
CustomOrderDefinition child = 6;
}
message OCOOrderDefinition {
CustomOrderDefinition other = 1;
int32 other_ticks = 2;
api.RelativeSide other_side = 4;
CustomOrderDefinition child = 3;
}
message PricerOrderDefinition {
int32 price_offset_ticks = 1;
double price_factor = 2;
CustomOrderDefinition child = 3;
}
message DynamicOrderDefinition {
string dynamic_order_type = 1;
map<string, DynamicOrderParam> order_params = 2;
@@ -203,6 +216,8 @@ message OrderState {
TriggerOrderState trigger = 21;
CoverOrderState cover = 22;
OffsetOrderState offset = 24;
OCOOrderState oco = 25;
PricerOrderState pricer = 26;
DynamicOrderState dynamic = 255; // do not use anything bigger than 255, or things will break
}
@@ -276,6 +291,8 @@ message TopOrderState {}
message TriggerOrderState {}
message CoverOrderState {}
message OffsetOrderState {}
message OCOOrderState {}
message PricerOrderState {}
message DynamicOrderState {}
enum OrderStatus {
+1
View File
@@ -14,6 +14,7 @@ namespace internal {
using namespace ::google::protobuf;
using namespace bts::expression;
using namespace bts::util::proto;
using std::vector;
ConfigValueQueue::ConfigValueQueue(IPropertyEvaluator& evaluator) :
_eval(evaluator),
+4 -3
View File
@@ -110,6 +110,7 @@ message CMEOptions
// Prevents parsing trades/rfqs/doing anything not required for quoting
optional bool quoter_mode = 6;
optional bool verbose_ticker = 7 [default=false];
}
message RecordOptions {
@@ -122,14 +123,14 @@ message RecordOptions {
// Replay options
//
message ReplayOptions {
optional string host = 1 [default = "mdreplay"];
optional string base_path = 2 [default = "/md"];
optional string file_name = 3 [default = "options.coconut"];
optional string url = 1 [default = "http://mdreplay.bluetradesys.local/spark/futures.coconut"];
// 2.0 = double speed, 0.5 = half speed
optional double speed = 11 [default = 1.0];
optional bool interactive = 12 [default = false];
optional string fallback = 20 [default ="data_files/futures.coconut"];
}
message RelayOptions {
-1
View File
@@ -3,7 +3,6 @@ package bts.config;
message PerfLogCfg {
optional bool active = 1 [default=true];
optional uint32 recent_traces_size = 2 [default=140123];
optional uint32 max_rows = 3 [default=10000123];
optional uint32 entry_batch_size = 4 [default=200];
}
+10
View File
@@ -3,4 +3,14 @@ package bts.config;
message Spreader{
optional uint32 n_failed_iocs = 10 [default=20];
//if this is set to true, the spreader internally
//generates fake fills to keep the cache (data and
//instruction) warm
message CacheWarming{
optional bool enable_fills = 10 [default=true];
optional bool enable_child_order_activate = 15 [default=true];
optional double fill_period_low = 20 [default=10];
optional double fill_period_high = 30 [default=50];
}
optional CacheWarming cache_warming = 20;
}
+1
View File
@@ -35,6 +35,7 @@
#include <stdlib.h>
#include <vector>
using std::vector;
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/stringpiece.h>
@@ -50,6 +50,7 @@
#include <stack>
#include <limits>
#include <vector>
using std::vector;
#include "text_format.h"
+8
View File
@@ -66,6 +66,14 @@ enum Side {
SIDE_SELL = 50;
}
enum RelativeSide {
RELATIVESIDE_UNDEFINED = 0;
RELATIVESIDE_OPPOSITE = 1;
RELATIVESIDE_SAME = 2;
RELATIVESIDE_BUY = 49;
RELATIVESIDE_SELL = 50;
}
enum PutOrCall {
PUTORCALL_PUT = 0;
PUTORCALL_CALL = 1;
Loaded 100 of 209 files, more files were not shown because too many files have changed in this diff. Show more