Compare commits

...
Author SHA1 Message Date
John Colvin be68e006bf fix (rec rept): Use tick-factors to avoid rounding errors
Bugs (fixed):
  * Reconcile Report can show false positive price mismatch

  Cause: The epsilon const (1E-12) used in the price comparison too small.
  Evidently, the Deribit-position prices provided to the Reconcile Report are
  only accurate up to 9 decimal places.
2022-07-20 09:37:31 -05:00
John Colvin b1a1f83ea8 ui: Hardcode dark theme 2022-07-20 09:37:31 -05:00
John Colvin 9495435780 fix (fills view): Change side col base class row type to the vm
Bugs (fixed):
  * In the Fills window, side column cells are empty
2022-07-20 09:37:30 -05:00
John Colvin e3d9b59759 refactor: Add get bg/fg delegates to RenderColumnBase
These colors are frequently functions of the rows; now such cases don't require
implementation in classes that derive from RenderColumnBase
2022-07-20 09:37:30 -05:00
John Colvin eb0f6ae25a chore (ui): Hook up background setting in OrderTypeColumn 2022-07-19 16:32:44 -05:00
John Colvin a9d72c22fb fix (ui preemptive): Bind horiz align setting to horiz content align
Bugs (fixed)
  * (preemptive) The OrderTypeColumn root border doesn't span the width of the
    column.  This would happen if the column's background was a
    non-transparent brush, and horizontal alignment wasn't stretched.
2022-07-19 16:29:46 -05:00
John Colvin caf5463565 ui: Enable grid background setting in all windows
And remove bool props that were used to toggle this behavior
2022-07-19 15:27:34 -05:00
John Colvin eb5290932f chore (vs graph): Add tick_line_color setting 2022-07-19 15:27:34 -05:00
John Colvin a0fb42f1cf fix (vs graph): Actually use axis_line_color setting in vm
Bugs (fixed):
  * The vs graph axis line color setting is ignored
2022-07-19 15:27:34 -05:00
John Colvin a450d6447a chore: Show color name in ColorNotFoundException msg 2022-07-19 15:27:33 -05:00
John Colvin db22dc2853 chore: Clean BTSColorExtension 2022-07-17 12:58:59 -05:00
John Colvin d042da8708 chore: Add 'Pure' attr to is_null_or_empty ext 2022-07-17 12:58:02 -05:00
John Colvin bed44db642 refactor: Clean up ReflectionHelper a bit
* Rename '(static_)property_delegates_of_type' -> '(static_)property_getters',
  and include name w/ prop getters
* Rename 'FindApplicableConstructor' -> 'get_constructor'
* Remove unused fns
2022-07-17 12:58:02 -05:00
John Colvin 9c5ac2eb19 fix (ui): Validate width/height before updating DragRectAdorner 2022-07-14 00:21:37 -04:00
John Colvin bec0e7dd15 chore: Clean up ui settings classes
* Move most settings files into new dir 'Model/Settings'
* Conform code style to our current practices
2022-07-14 00:21:37 -04:00
John Colvin 9c7013082d fix: Add null-check
A null-ref exception surfaced when running client w/ low bandwidth
2022-07-14 00:21:37 -04:00
John Colvin 80a9df9d73 ui: Speed up expand/collapse animation in settings dialogs 2022-07-14 00:21:37 -04:00
John Colvin 7040af5545 chore (refactor): Move synth mgmt settings classes into sep files 2022-07-14 00:21:37 -04:00
John Colvin fe8866118d fix: Gather individual win settings on dispatcher thread
In practice, window-states live on their respective dispatcher threads.
Window settings factories shouldn't be expected to be thread-safe.
2022-07-14 00:21:36 -04:00
John Colvin d699f85784 fix (vs ui): Don't clip vs time sched ui 2022-07-14 00:21:36 -04:00
John Colvin 0a797c0cfb ui (vs grid settings): Constrain window height 2022-07-14 00:21:36 -04:00
taha afzal 89d5b25cc7 For EmMDListener, added a limit of 5 pending calls for positions, after which the counter is reset is positions are re-requested 2022-07-12 17:03:19 -04:00
Taha Afzal 3e10d403b4 Combo Report now listens to the sectups in the report configuration 2022-07-12 09:35:42 -04:00
Taha Afzal 1ebf06d49a Slide report filters the securities based on the security tuples passed in the report 2022-07-12 09:35:42 -04:00
Taha Afzal 2be857a851 Forcing qty's to be rounded to 2 2022-07-12 09:35:42 -04:00
John Colvin 1de22a82e8 fix (combo settings ui): Refresh 'result' when sec criteria changes
Bugs (fixed):
   * In Combo settings dialog, security criteria changes aren't committed to
     server if they are the last prop changed before OK click
2022-07-12 01:00:51 -04:00
John Colvin f275308cc8 build (client cpp): Remove ZERO_CHECK.vcxproj from spark_client.sln
The new cmake generates ZERO_CHECK.proj instead, which doesn't need to be
included in the sln. I think this change was introduced in v 3.22.

Devs: This won't break the build for older versions of cmake, although you may
need to manually touch "CMakeLists.txt" when you add/remove build src files
2022-07-12 01:00:44 -04:00
taha afzal 79de0dd4d8 Removed exchange from sub acocunt config 2022-07-11 21:13:05 -04:00
taha afzal 5cedf74406 Merge branch 'spark_crypto.multiple_accounts' into spark_crypto.dev 2022-07-11 17:44:02 -04:00
taha afzal e5de6b4ad7 Changed the relationship of internal account to sub account to simple 1:1 2022-07-11 17:28:53 -04:00
John Colvin e467195de1 chore (combo vm): Let end observer call OnDispatcher
This behavior could arguably be coupled with a Subscribe call, since its whole
purpose is to ensure subscription callbacks occur on the dispatcher thread.
2022-07-11 17:22:44 -04:00
John Colvin 913a5b4a7e ui (combo settings): Show contract picker 2022-07-11 17:22:44 -04:00
John Colvin feb8bd9b79 ui (slide settings): Show contract picker 2022-07-11 16:55:23 -04:00
taha afzal 846ecfa776 Fixed the reconcile issue where if the security existed in multiple accounts it was getting surpressed in one 2022-07-11 13:27:10 -04:00
taha afzal d98fb399a8 Exchange Positions can now be obtained for multiple sub accounts 2022-07-09 01:40:28 -04:00
taha afzal 4a1c1d023a Changes to accomodate the EM API change for mulitple accounts 2022-07-06 16:42:04 -04:00
taha afzal 43cba548f4 Adding some details to the logs to track order flow 2022-06-24 15:05:15 -04:00
taha afzal 772910ffe5 Fixing filled qty's fractional part not being filled on the server 2022-06-23 14:38:57 -05:00
John Colvin 767179caf7 chore (man fills): Format qty w/ sec metadata config 2022-06-23 14:38:57 -05:00
John Colvin ee4a9150b8 refactor (man fills): Rename 'size' members 'quantity' 2022-06-23 14:24:04 -05:00
John Colvin 58914fa703 chore: Replace remaining refs to uint 'filled' fn w/ double impl 2022-06-23 14:24:04 -05:00
John Colvin ba40e7044a fix (ladder, preemptive): Fix typo in _fmt_mkt_depth_item
Bugs (fixed):
   * The _fmt_mkt_depth_item fn potentially will return the result of the
     delegate.ToString(), instead of invoking the delegate and returning the
     result
2022-06-23 14:10:15 -05:00
John Colvin 010d0073fe chore: Set BTC qty display config defaults 2022-06-23 02:05:23 -05:00
John Colvin 40210ce42e chore: Remove unnecessary price_display config default 2022-06-23 01:35:22 -05:00
John Colvin 59cdafba21 fix: Don't cast manual fill qty to uint 2022-06-23 01:22:09 -05:00
John Colvin fe6226baa5 ui (reconcile rep): Match all undefined positions
Now, all positions without real non-zero quantities are considered matches
2022-06-23 01:19:27 -05:00
John Colvin 45987c7652 feat: Show fractional qty in orderbook Filled col 2022-06-22 16:04:24 -05:00
John Colvin a18ce97fb4 feat (ui): Support fractional qtys for order entry 2022-06-22 15:38:38 -05:00
John Colvin 13d5080bbc refactor: Shorten modify/revert cmd prop names
Also consolidate modify_price/qty fns into single modify_order fn
2022-06-22 15:38:38 -05:00
John Colvin 9f07a36d1d refactor: Move order-update-desc fn into OrderUtils for gen use 2022-06-22 15:38:38 -05:00
John Colvin bc2e7f428a chore: Add formal/consistent numeric exceptions/messages 2022-06-22 15:38:38 -05:00
John Colvin 53bfbdd349 fix: Sync 'has_value' prop for qty param
Bugs (fixed):
   * Can't tick qty up/down in the orderbook right panel (clicking the
   button has no discernible effect)
2022-06-22 15:38:38 -05:00
John Colvin 174eac9a59 refactor: Move OrderParamsVM into own file
OrderBookVM.cs was (and frankly still is) massive.  Too massive
2022-06-22 15:38:38 -05:00
John Colvin 3775b86d9e refactor: Rename 'size_' props 'quantity_' to be consistent 2022-06-22 15:38:38 -05:00
John Colvin 5e1c6d6209 fix build (windows): Don't include stdint-uintn.h on windows 2022-06-22 15:38:37 -05:00
taha afzal 0d0fb036ab EmMDListener now get_open_orders and logging the open orders 2022-06-22 15:38:37 -05:00
taha afzal f8668802ab Fixing oder updates on fractional quantity orders (just a few lines) 2022-06-22 15:38:37 -05:00
taha afzal c22a1382a1 Fractional qtys now work on the server (need some client side work) 2022-06-22 15:38:37 -05:00
Taha Afzal 941a0d91cc Enabled Combo report to show fractions (ITradeLow had size of type int) 2022-06-13 20:01:47 -04:00
taha afzal 60456e4225 Deribit market data is blanked out now if the connection to Deribit is lost 2022-06-10 09:54:22 -04:00
John Colvin 440e28489a build: Update libspark CMakeDeps_win 2022-06-09 13:49:55 -04:00
John Colvin 3da0f4eedc ui: Indicate price discrep w/ subtler visual than qty discrep 2022-06-09 13:49:55 -04:00
Taha Afzal 497abfb443 Fixing Futures PNL in slide 2022-06-09 00:15:23 -04:00
Taha Afzal 7b04a7849b Future delta fixed in Slide 2022-06-08 15:56:24 -04:00
taha afzal e14b1e0b07 Limiter does not use StaticLimiter anymore because Deribit and Options are included in Risk enforcement now 2022-06-08 15:55:24 -04:00
John Colvin 2121ce2841 fix build (server gcc): Remove noexcept specifier from copy/move ops
The gcc compiler was deleting the copy/move operators declared in the
MarketDataSubscription class.  This behavior was appropriate, as those
operators were declared with the 'noexcept' specifier, while the
copy/move operators of one of its members, params_ (of a proto-generated
type), lacked the 'noexcept' specifier.
2022-06-08 13:43:12 -04:00
John Colvin c22e99941e fix build: Disable ccapi dependent code on windows
It seems the ccapi lib doesn't support windows.  External market data
subscription code only needs to be built on the server anyways.
2022-06-08 11:42:10 -04:00
John Colvin 3da646dc8a fix build: Remove unnecessary import from binance-md proto
This removes an 'unused import' warning on build
2022-06-08 11:12:13 -04:00
John Colvin fca675d43f feat: Add option/deribit params to risk ui 2022-06-07 23:20:59 -04:00
John Colvin a30523744d feat: Implement ftx md subscription
Run 'sparkd ladder-demo' to check it out
2022-06-07 23:20:59 -04:00
John Colvin 80f5117c34 chore: Add is_empty fn to BookLevel
This pre-emptively fixes the BookSide::is_sorted fn, as it references
the previously non-existent BookLevel::is_empty fn
2022-06-07 23:07:33 -04:00
John Colvin f77f73ec36 fix: Fix typo in MarketDataError type param 2022-06-07 23:07:33 -04:00
John Colvin 2385cf0d1b refactor: Add add/remove fns to composite listener for convenience 2022-06-07 23:07:33 -04:00
John Colvin bc778ad5bb refactor: Rename CompositeListener -> CompositeMarketDataListener
Obviously a better, more descriptive name, and it matches the filename
(the oldname must have been an accident)
2022-06-07 23:07:33 -04:00
John Colvin acb9c35d3b logging: Add ccapi log adaptor 2022-06-07 23:07:33 -04:00
John Colvin b8473e2632 Update externals to get ccapi lib 2022-06-07 23:07:33 -04:00
John Colvin 61b4696574 fix: Don't print bogus level in LadderLivePrinter
This is used when running 'sparkd ladder-demo'

Bugs (fixed):
  * Sometimes it prints a bogus level

  cause: The 'last_ask' iterator is pointing just after the last element
  (i.e,. asks.end(), a bogus value)
2022-06-07 23:07:33 -04:00
John Colvin 91a79a5d96 refactor: Simplify md gateway/binance subscription
* Temporarily get rid of the register_listener fn, and just use
  subscribe/unsubscribe to immediately connect/disconnect listeners to
  exchange feeds. The 'register, then subscribe per sec-id' paradigm is
  tricky to implement without access to security ids.
2022-06-07 23:07:33 -04:00
John Colvin 23927edf46 fix: Add missing log msg param 2022-06-07 22:44:33 -04:00
John Colvin 6c03e605b8 refactor: Consolidate md listener management into MarketDataGateway
This responsibility was awkwardly split between MarketDataGateway and
BinanceDepthStreamSite before, which made code confusing/hard to follow.
2022-06-07 22:44:33 -04:00
John Colvin 2e201159d8 refactor: Move BinanceDepthStreamParams into own file 2022-06-07 22:44:33 -04:00
taha afzal 5d56a8e440 Added some comments and imporves the logs 2022-06-06 17:27:08 -04:00
taha afzal 7097c85555 Fixing the SQLite error on archive_theos that was crashing the server on a duplicate key assertion 2022-06-06 15:14:57 -04:00
John Colvin bf4c8e252f Add install dir to gitignore 2022-06-03 22:41:16 -04:00
John Colvin 866cf33cd4 build: Set CMAKE_INSTALL_PREFIX (for deployment)
Run 'cmake --build <path_to_build> --target install' to create a self-
contained executable sparkd in the 'install' dir at the root of the repo
2022-06-03 22:35:44 -04:00
John Colvin 4561560b46 Remove redundant 'build' items in gitignore 2022-06-03 22:32:07 -04:00
John Colvin bbadbf8e16 build: Move .cmake files to cmake dir (from tools) 2022-06-03 10:42:32 -04:00
John Colvin 68d8659115 fix (ui/slide): Fix greek tick-display formatting
Rather than fix the format fn for the old type, TickDisplaySettingsTuple,
convert params to the newer type, TickDisplaySettings, then call that type's
formatting fn (which isn't broken).
2022-06-03 01:16:03 -04:00
John Colvin dd008962a7 ui (slide/vs settings): Adjust expand/collapse durations 2022-06-03 00:42:05 -04:00
John Colvin e856e7e58f style: Add 'at_most/least' aliases for min/max ext fns
Also add documentation (for completeness sake)
2022-06-03 00:41:04 -04:00
John Colvin 634d8e1aeb fix (pre-emptive): Add null check in SecurityFormatter 2022-06-02 17:44:38 -04:00
John Colvin eaa9376577 fix (pre-emptive): Add some null checks in ContractLegEnumerable
And clean up the code a bit while we're at it
2022-06-02 17:44:38 -04:00
John Colvin 3fb70fd645 fix (contractpicker): Don't init SecurityMap w/ empty dict
Bugs (fixed):
  * The create-synth dialog crashes when picking a new leg's security
2022-06-02 17:44:38 -04:00
John Colvin b793c75aa8 Add some null checks to LegSpreaderParamsTuple 2022-06-02 17:44:38 -04:00
John Colvin cb26b9af39 fix (contractpicker): Remove SecurityMap CoerceValueCallback
This was breaking the binding so that the view had a different
security-map instance than the vm
2022-06-02 17:44:38 -04:00
John Colvin f8059cc87e build: Add verbosity opt to buildspark.py 2022-06-02 17:44:38 -04:00
John Colvin 07fe19ecdc build: Symlink emumba license in build dir
So we don't have to do it manually
2022-06-02 02:15:14 -04:00
John Colvin a292fe87e1 build: Set up cmake 'install' build target
The 'install' build target creates a self-contained (deployable) sparkd
package. It copies the sparkd executable and its dependencies into a
single directory (no symlinks), which can then be copied/deployed to
another machine.

Run `cmake --build . --target install` to install sparkd in the
directory defined by the CMAKE_INSTALL_PREFIX variable.
2022-06-02 01:32:17 -04:00
John Colvin 03d915b55c Update externals to get emumba deribit lib 2.2.8 2022-06-02 00:47:42 -04:00
John Colvin cc318535e9 fix (slide settings ui): Add show_commas prop to GreekDisplayVM
Bugs (fixed):
  * The 'show commas' check box doesn't do anything in slide settings ui

    Cause: The view is bound to a non-existent prop in the vm
2022-06-01 19:28:13 -04:00
John Colvin 9d245f3243 ui (vs settings): Wrap body in scrollviewer 2022-06-01 19:02:42 -04:00
John Colvin 6d7f95ac8e ui (vs settings): Change radio buttons to dropdown
The radio buttons take up too much space
2022-06-01 19:02:42 -04:00
John Colvin 9d9df76f4e refactor: Clean up KeyedTemplateSelector
* Use new lang feats
* Run formatter
* Split up classes into separate files
* Move into Controller dir (per the MVCVM paradigm)
2022-06-01 19:02:42 -04:00
John Colvin a850082f44 refactor: Move StringExtensions to ns Spark.Core 2022-06-01 19:02:42 -04:00
John Colvin 521150a73b refactor: Clean up StringExtensions
* Use new lang feats
* Run formatter
2022-06-01 19:02:42 -04:00
John Colvin ed5f3fe740 ui (slide settings): Change param validation msgs
Change 'Specify' to 'Choose'
2022-06-01 19:02:41 -04:00
John Colvin fd6fdd9768 Refresh radio-button-member 'IsChecked' when member-val changes 2022-06-01 19:02:41 -04:00
John Colvin 73bf104e9f fix: Add null check
Also use null coalesce syntax to clean up existing null checks
2022-06-01 19:02:41 -04:00
John Colvin 24640e65b1 fix (pre-emptive): Add null check 2022-06-01 19:02:41 -04:00
John Colvin eadfc38a69 refactor: Use nullability feat in ExceptNull, DisposeAll fns 2022-06-01 19:02:41 -04:00
John Colvin 098ee36c3a fix: Init NotifyCollectionChangedEventArgs w/ correct args
Bugs (fixed):
  * The ObservableAggregateCollection.Aggregator.Insert fn causes an
    ArgumentException if the collection to be inserted is non-empty. This seems
    to happen because the NotifyCollectionChangedEventArgs is improperly
    constructed (the collection-tuple is passed as the 'changedItem' arg).

  * The ObservableAggregateCollection.Aggregator.Insert fn appends existing
    items to the end of the aggregate collection (instead of inserting them in
    the appropriate index).
    Note: This bug was only revealed after the first bug was fixed.
2022-06-01 19:02:41 -04:00
John Colvin f4ed4d38f1 refactor: Change collection aggregator to use IReadOnlyList
It was previously accepting IReadOnlyCollection args, but the
ObservableCollection paradigm generally uses indexed lists
2022-06-01 19:02:41 -04:00
John Colvin 2ed3eaa325 refactor: Check if list already instantiates IList<T>
Before creating a new MutableWrapper<T>
2022-06-01 19:02:41 -04:00
John Colvin 3a7a02244b refactor (ui): Use ExpandedContentSelector in vs win 2022-06-01 19:02:41 -04:00
John Colvin 79258b9404 fix (slide): Observe IObservables OnDispatcher 2022-06-01 10:11:26 -04:00
John Colvin 6376802d04 ui (slide): Use ExpandableContentSelector 2022-06-01 10:11:26 -04:00
John Colvin 2784e7652d ui (control): Add ExpandedContentSelector for modal section-expansion 2022-06-01 10:11:26 -04:00
John Colvin 5b3925fae0 fix: Set GridSettings.enable_background_color in settings vm 2022-06-01 10:11:26 -04:00
John Colvin 077f6050f3 ui (login): Add F5 'refresh' cmd to retry connecting to server 2022-06-01 10:11:26 -04:00
John Colvin 791dd62b67 fix (ui): Fix typos in vs settings editor xaml
* Remove non-existent xmlns

* Change element-name 'curve_ops_gb' to 'StandardCurveOpsView'.  The _gb suffix
  doesn't make sense bc the element is no longer a GroupBox, and the new name
  is stylistically consistent with the other section-view element-names

* Change 'Market Fit View' to 'Market Fit'
2022-06-01 10:11:15 -04:00
John Colvin 2364cda362 ui: Tweak expand/collapse animation
Use shorter duration for collapsing, and longer for expanding
2022-06-01 00:00:57 -04:00
John Colvin aca4365e8d fix (pre-emptive): Add null check 2022-05-31 16:43:22 -04:00
taha afzal cac857a3a7 Busted fills filtered out of the PositionService position calculations 2022-05-30 15:38:08 -04:00
John Colvin ed38ce958d build: Resurrect web build 2022-05-28 11:40:45 -04:00
Taha Afzal ed4b9b7426 Added is_active to ITradeLogRow, and changed Combo and Slide to use that 2022-05-26 19:31:13 -04:00
Taha Afzal e4468f056d Filtering out busted fills in Slide 2022-05-26 19:17:23 -04:00
Taha Afzal 4b580b407e Adding FillStatus to ITradeLogRow and filtering the busted fills out in Combo 2022-05-26 19:08:47 -04:00
taha afzal b575612b07 Fixing Busting of fills on ResetPositions 2022-05-26 18:39:19 -04:00
John Colvin b506b971a4 feat: Init order ticket w/ default account from ladder profiles 2022-05-26 15:44:02 -04:00
John Colvin c50f322dc1 refactor: Remove 'where class' constraint from FirstAsyncTask
The constraint didn't seem to serve a purpose
2022-05-26 12:57:02 -04:00
John Colvin 3a61f4d81d ui: Add default-background control to grid settings dialog 2022-05-26 12:57:02 -04:00
John Colvin a2b2de9783 feat: Reconcile Report 2022-05-25 14:28:58 -04:00
John Colvin b2a6927b4b Enable all column settings in mview (for all cols) 2022-05-25 14:28:57 -04:00
John Colvin 80dec4e1e2 ui: Fix typo to enable column background in GridSettingsView 2022-05-25 14:28:57 -04:00
John Colvin 77c7802496 Set cell-view's DIYGrid.Column when syncing w/ column geometry 2022-05-25 14:19:04 -04:00
John Colvin cec2687085 ui: Increase default 'Security' col width
Many Deribit securities are wider than the previous col width
(particularly options)
2022-05-25 14:19:04 -04:00
John Colvin ac118993d5 refactor: Change ManualFill.quantity to double 2022-05-25 14:19:04 -04:00
John Colvin 7634ecf730 refactor: Break up massive file Update.cs
Into one file per class
2022-05-25 14:19:04 -04:00
John Colvin 309d1fa287 refactor: Remove LegacyTableUpdate class 2022-05-25 14:19:04 -04:00
John Colvin 9231a91fb4 Fix typo in Update.merge fn
Bugs (fixed):
   * When merging updates, a new ChangeDict is always instantiated
   (sometimes unnecessarily).  This was causing a performance hit, but
   not actual bad/incorrect behavior, so it went unnoticed for years
2022-05-25 14:19:04 -04:00
John Colvin f6f928a693 refactor: Move MarketDataAuxiliaryModel into Model dir 2022-05-25 14:19:03 -04:00
John Colvin 467216439b refactor: Move PositionModel classes into own files 2022-05-25 14:19:03 -04:00
John Colvin c63e73ab7c refactor: Move SparkObservableExtensions into own file
And rename class ReactiveObservableExtensions
2022-05-25 14:19:03 -04:00
John Colvin 74fcacd800 Clear 'raw' (unfiltered) table changes on filter-updates
Otherwise, it would repeat the changes from the last data-update, and
break the incremental sequence
2022-05-25 14:19:03 -04:00
John Colvin c1c46f01ab refactor: Use DispatcherObservable class to avoid op chains 2022-05-25 14:19:03 -04:00
John Colvin 77083a1fa6 fix: Don't bypass Dispatcher.InvokeAsync in OnDispatcher ext
Otherwise the updates may not be received in order
2022-05-25 14:19:03 -04:00
John Colvin 5303f290b1 refactor: Move sec metadata utils into SecurityMetadataStore 2022-05-25 14:19:03 -04:00
John Colvin 895871c94b refactor: Move SecurityCriteria classes into spark_core
Also move IBus there bc some SecurityCriteriaExtensions depend on it
(and spark_core seems more appropriate for IBus anyways)
2022-05-25 14:19:03 -04:00
John Colvin 3bff50b764 diag: Add TableUpdate.description ext
For diagnostic logging/tracking down bugs
2022-05-25 14:19:03 -04:00
John Colvin 86b7802b3b Use RadioButtonGroupManager.Value prop instead of DataContext
This more clearly defines the behavior
2022-05-25 14:19:03 -04:00
John Colvin 4ff9aaf037 refactor: Clean up DIYGridFilterModel 2022-05-25 14:19:03 -04:00
John Colvin 99f7827e7e refactor: Clean up RadioButtonGroupManager/Map 2022-05-25 14:19:03 -04:00
John Colvin b67ac5c849 Simplify slide settings view by using RadioButtonGroupManager (not map) 2022-05-25 14:19:03 -04:00
John Colvin 0777f01607 fix: Remove il-advised SelectedItem(Binding) dp
It doesn't make sense to try to normalize the binding for different
groups into a single binding in the group manager
2022-05-25 14:19:03 -04:00
John Colvin 222dbf5443 refactor: Move RadioButtonGroupManagerMap into own file 2022-05-25 14:19:03 -04:00
John Colvin 9434f61030 fix: Make GroupManagerMap an Attached dp
It always should have been attached (analagous to a static prop)
2022-05-25 14:19:03 -04:00
John Colvin 9199594756 fix: Add null check for put/call_points in VolSurfaceDataFunctions 2022-05-25 14:19:03 -04:00
John Colvin fc9318a831 ui: Refine vs settings dialog
Make it look more like combo/slide settings dialogs
2022-05-25 14:19:03 -04:00
John Colvin e3fc28f082 fix: Wrap algometadata proto list in single class
Bugs (fixed):
   * An exception is thrown when deserializing
     AlgoDefinitionPersistedMetadata array
2022-05-25 14:19:03 -04:00
John Colvin 9cb7b84f57 Only recreate TViews when necessary in RXCollection 2022-05-25 14:19:03 -04:00
John Colvin 2689ed806d fix: Add null check in VolSurfaceDataFunctions.get_symbols 2022-05-25 14:19:03 -04:00
John Colvin 5999e7856f fix: Add null check for sec metadata in MDDaemon 2022-05-25 14:19:03 -04:00
John Colvin 96ad67b020 fix: Ensure ShellModuleVM.MenuContent is created at most once 2022-05-25 14:19:03 -04:00
John Colvin 47d5b95e13 ui (exp params): Add 'Set Driver to Nearest Exp' menu item 2022-05-25 14:19:02 -04:00
John Colvin 12108e6046 fix: Fix typo in 'abs' ext (should accpet INumber<T>) 2022-05-25 14:19:02 -04:00
John Colvin 021bdb8c23 Add ObservableHashSet 2022-05-25 14:19:02 -04:00
John Colvin 470f6c0988 Add Opacity option to ColorExtension (for xaml) 2022-05-25 14:19:02 -04:00
John Colvin c8b87b4f79 Remove the ill-advised FontFamily enum
The library of potential font families to choose from is endless, so it
doesn't make sense to limit a user's options to a small set of arbitrary
presets
2022-05-25 14:19:02 -04:00
John Colvin 9d7e16fbf7 refactor: Move FontFamily exts into own file
This resolves some nagging namespace conflicts w/ FontFamily (in
System.Windows.Media and mbts.ui.utility.text)

TODO: Get rid of mbts.ui.utility.text.FontFamily (it was an ill-advised
enum to begin with)
2022-05-25 14:19:02 -04:00
John Colvin 5a45d5e12a fix: Ensure AlgoData IObservable fires at least once
Bugs (fixed):
   * The algo dropdown in ladder/ticket is empty
   Note: this bug was exposed as side effect of a recent change to
   prevent the TableUpdate Filter ext from firing empty TableUpdates
2022-05-25 14:19:02 -04:00
John Colvin c793ec78a2 Don't send empty updates in TableUpdate Filter ext 2022-05-25 14:19:02 -04:00
John Colvin 7b2b7c5854 refactor: Get rid of 'semi_transparent' brushes in BTSColors
Doesn't seem worth the clutter
2022-05-25 14:19:02 -04:00
John Colvin 327615c9ac refactor: Move 'position' utils from OrdersModel to PositionModel
OrdersModel contains way too much "miscellaneous" code.  This will
reduce at least some of the clutter.
2022-05-25 14:19:02 -04:00
John Colvin 8e5d94b5e7 refactor: Move TickDisplayConverter into mbts.ui.converters ns
This is where all the other IValueConverter classes are defined
2022-05-25 14:19:02 -04:00
John Colvin bd76a1f260 ui: Only expand one section at a time in slide settings dialog 2022-05-25 14:19:02 -04:00
John Colvin 1df2695f50 refactor: Clean up FillsVM 2022-05-25 14:18:57 -04:00
John Colvin 67d33a3315 Add null-check when disposing ObservableAutoWrapper item-hooks 2022-05-25 14:07:21 -04:00
John Colvin c49cd3a06e refactor: Clean up DIYGridRowsManager and related files/types
* Rename class suffix 'Manager' -> 'Model'
* Move classes into own files
* Put column-related classes in columns dir
* Enable nullable
* Run formatter
2022-05-25 14:07:21 -04:00
John Colvin 6c0545f566 fix: Don't deserialize AlgoDefinitionMetadata[] w/ length prefix
Bugs (fixed):
   * AlgoDefinitionMetadata[] deserialization fails
2022-05-25 14:07:21 -04:00
John Colvin f0eee365f9 fix: Catch & log deserialization exceptions
Rather than silently catching the exception upstream
2022-05-25 14:07:21 -04:00
John Colvin 274db506a9 Clean up DiscreteValuesFilterVM 2022-05-25 14:07:21 -04:00
John Colvin 1e5c56f3a7 refactor: Make key param optional in TableUpdate Filter ext 2022-05-25 14:06:49 -04:00
John Colvin 871c7a131f refactor: Move Position extensions to own file in spark_api 2022-05-24 12:25:16 -04:00
John Colvin 7642d73f39 Add join_table fn to SecurityStore 2022-05-24 12:25:16 -04:00
John Colvin ef69dfa646 refactor: Add 'table' subscription fns to generated proto services
* Provides a simple convenience, as nearly all api subscriptions made on the
  front-end are converted to TableUpdates anyways

* Can help reduce overhead by instantiating TableUpdate subscriptions
  lazily, and by using one internal TableUpdate subscription to provide
  notifications to all observers
2022-05-24 12:25:16 -04:00
John Colvin 377be5030f style: Clean up pb.cs templates (generated code) 2022-05-24 12:25:16 -04:00
taha afzal 896af55e79 Added commented to document flow of ExchangePosition 2022-05-24 12:24:47 -04:00
Taha Afzal b9a4a2c148 Added right click context menu item in the sheets to launch ladders 2022-05-23 15:36:49 -04:00
Taha Afzal e9f6d096cf Disabling tasking context menu items from the sheet 2022-05-23 14:46:47 -04:00
taha afzal 25d4c54284 Added account_id to ExchangePosition 2022-05-23 11:51:10 -04:00
taha afzal e4291e1c51 Adding account to ExchangePosition 2022-05-19 18:16:46 -04:00
taha afzal 5c11708728 Fixing assert on_get_all_position callback from EM 2022-05-18 17:56:06 -04:00
taha afzal 73a301192f Fixing ExchangePosition's qty (unsigned uint related bug) and exchange 2022-05-18 17:14:39 -04:00
Taha Afzal d972564d34 Clip defaults changed 2022-05-18 01:16:39 -04:00
taha afzal e66a2d4663 Rejected orders now show up in the Orderbook UI 2022-05-18 00:42:00 -04:00
Taha Afzal f92e13d898 Logging the key of the placed order 2022-05-16 16:03:46 -04:00
John Colvin 3d0698b326 task: Set ManualFill.FillType to 'AdminDay' 2022-05-16 15:57:28 -04:00
Taha Afzal 1e0ab86a24 MD entitlements turned off temporarily until we can add the settings to Risk Admin (web) 2022-05-12 18:02:22 -04:00
Taha Afzal caa29b9513 Reducing market data related logging 2022-05-12 16:21:42 -04:00
Taha Afzal c793768918 Bug with VolSurfaceUsage fixed 2022-05-12 00:09:37 -04:00
John Colvin 0132a0cff6 ui (exp params, combo): Format exps with month abv & day
This formatting is consistent with the rest of the system.  Furthermore, it
ensures all sym/exp combinations have unique string reps (some symbols can have
multiple exps in one month, such as ETH).
2022-05-11 15:19:50 -04:00
John Colvin f83b6ee898 ui (slide): Prevent last-trade & swipe-sum from overlapping 2022-05-10 13:38:36 -04:00
John Colvin dc071dfa56 fix: RaisePropertyChanged when vm 'HasErrors' changes 2022-05-10 13:34:29 -04:00
John Colvin fbfd601270 ui: Refine slide settings dialog
* Unify greeks configuration/display settings into one section
* Replace tabs with modal expandable sections (like in the analytics
shell module view)
2022-05-10 13:34:29 -04:00
John Colvin 9b5aea2458 refactor: Abstract out modal expand/collapse animation/behavior
From the analytics module view (so it can be used by other windows)
2022-05-10 13:31:57 -04:00
taha afzal 904ef92ece Added reset_position to PositionService 2022-05-09 14:40:44 -04:00
John Colvin 74e950d459 ui: Don't filter manual fills 2022-05-07 17:51:44 -04:00
John Colvin e99caef2dc ui: Change 'Show Expanded' to 'Expand Symbols' in slide/combo 2022-05-07 16:42:15 -04:00
John Colvin 855e4a6ed8 ui: Change combo 'expand' icon to chevron right
It expands to the right (not down)
2022-05-07 16:40:16 -04:00
John Colvin 311b956461 Set manual fills' FillType to ADMIN_DAY (when creating) 2022-05-07 16:19:10 -04:00
John Colvin b3b308cd9d ui (fix): Set DIYGridLineAdorner.IsHitTestVisible to false
Otherwise it prevents click events from reaching the grid
2022-05-07 14:02:51 -04:00
John Colvin a8480a34ba fix: Detach DIYGridLineAdorner on dispose 2022-05-07 14:02:46 -04:00
John Colvin 3312637b8d dev/john: Add vscode json files for windows/client 2022-05-07 13:57:49 -04:00
John Colvin e6f7a82fb1 dev/john: Move 'vscode' json files into vscode/linux
They've always been specific to the linux/server code.  Moving them as such
to make room for windows/client specific settings files.
2022-05-07 13:57:49 -04:00
John Colvin 5b934de69a Add redundant checks to ensure readonly cells aren't copy/pasted in vs grid 2022-05-07 13:57:49 -04:00
John Colvin 0f78982f57 fix: Support copy/pasting in vs grid on readonly cell click
Only the option to copy the individual column value should be
hidden/disabled for readonly cells
2022-05-07 13:57:49 -04:00
John Colvin 18abbfc502 fix: Use vs grid's context menu rather than those of individual rows
Bugs (fixed):
   * Crash when copy/pasting in volsurface grid
2022-05-07 13:57:49 -04:00
John Colvin c3ae4c6dc5 refactor: Make VolSurfaceColumn.model readonly
It's never reassigned; should have been readonly to begin with
2022-05-07 13:57:09 -04:00
John Colvin 9b012649cd fix: Add nullcheck for hscrollbar in grid line adorner
Bugs (fixed):
   * A silent ArgumentNullException is thrown when opening volsurface windows
   during startup
2022-05-07 13:57:09 -04:00
Taha Afzal c126091155 VolSurfaceUsage is not read from config 2022-05-06 14:41:40 -04:00
taha afzal c2fee56496 Adding temporary vol surface usage to config (simplifying it to only have symbol because SecTup had serialization issues in C#) 2022-05-06 13:55:44 -04:00
taha afzal 5461dc77aa Added default config based risk limits for Deribit symbols 2022-05-05 20:39:47 -04:00
taha afzal 1b2a1c3fe3 Limiter can optionally get its value from config 2022-05-05 20:39:47 -04:00
Taha Afzal a83a4fdd4f UIOverrides for slide are ignored in the calcultor (were already disable din the UI for now) 2022-05-05 13:53:16 -04:00
Taha Afzal 4d4ee1f57c TC2 is constructed on the correct options now 2022-05-04 15:11:24 -04:00
John Colvin 2bec4ae09f ui: Hide position analysis filters in slide win
At least until they're actually implemented in model/calculation code
2022-05-04 15:07:14 -04:00
John Colvin e3b91909a6 Hook up combo conf vm ErrorsChanged callback once (in ctr) 2022-05-04 14:58:57 -04:00
John Colvin 116ba3f629 Add venue component to report risk-terms/opt-equiv params 2022-05-04 14:56:43 -04:00
John Colvin 0ce6f8e6a2 style: Enable nullable in ComboReportFuturesGrid 2022-05-04 14:53:44 -04:00
John Colvin 9447cb67d2 fix: Populate exps list used to generate cols in combo futs grid
Bugs (fixed):
   * Future positions aren't showing in combo report
2022-05-04 14:53:44 -04:00
John Colvin 92dacc5c3c ui: Use consistent sorting in risk terms/opt equiv dropdowns 2022-05-04 14:53:44 -04:00
John Colvin 766dfe9dd3 ui: Hide security criteria param in slide settings win 2022-05-04 14:53:44 -04:00
John Colvin 84ecb54efd ui: Change 'Volsurface' -> 'Vol Surface' in slide settings win 2022-05-04 14:53:44 -04:00
John Colvin 6ff8855dba refactor: Change report security list to SecurityCriteria 2022-05-04 14:53:44 -04:00
John Colvin 7f349cfa71 ui: Use converter to generate 'pretty name' for sec criteria clause 2022-05-04 14:53:44 -04:00
John Colvin 948b23addc fix: Don't add duplicate securities in slide config vm
Bugs (fixed):
   * Slide settings dialog shows duplicate security items in dropdown
2022-05-04 14:53:44 -04:00
John Colvin 7031bb6fbe fix (ui): Fix typo in slide settings dialog ok/apply cmd binding 2022-05-04 14:53:44 -04:00
John Colvin 15a04a1870 build: Temporarily disable web build
Until we can fix integration with dotnet 6
2022-05-04 09:23:32 -04:00
John Colvin 741c6d360a fix: Refresh slide-settings vm 'result' when included syms change 2022-05-02 17:32:32 -04:00
John Colvin c4f3ca26ef ui: Use new spark menu toggle style in combo win/vm 2022-05-02 17:29:30 -04:00
John Colvin 3403adc1ff fix: Hook up expanded/collapsed toggle in slide
Bugs (fixed):
   * Changing the view-format in slide doesn't do anything
2022-05-02 17:29:30 -04:00
John Colvin 410d3aaf20 ui: Use opacity to indicate 'checked' state in spark menu 2022-05-02 17:29:30 -04:00
John Colvin 34905f6053 Fix benign typo in exp params win menu item init 2022-05-02 17:29:29 -04:00
John Colvin 6a16d419af ui: Use checkmark icon for 'Checkable' items in spark win context menu 2022-05-02 17:29:29 -04:00
John Colvin cd23c1a5a1 fix (ui): Use 'opacity' to indicate enabled/disabled in spark menu
Bugs (fixed):
   * SparkMenuItems sometimes look disabled when they aren't (esp in
   AnalyticsExpirationParameters win)

In wpf, VisualStates in different VisualStateGroups shouldn't adjust
common properties.  A visual element can only be in 1 visual state at a
time.  When a visual element transitions to a new visual state, all
depepdency property changes associated with the transition to the
previous state are cleared.
2022-05-02 17:29:29 -04:00
John Colvin 18793f8cd9 ui: Add 'Swipe Sum' tooltip in slide 2022-05-02 17:29:29 -04:00
John Colvin c008147674 ui: Use DayMonthAbvDiff2000 format for last trade exp in combo/slide 2022-05-02 17:29:29 -04:00
John Colvin 47323c51c3 ui: Use normal font size of grid in combo 2022-05-02 17:29:29 -04:00
John Colvin 91f58620ac ui: Make '|' separator in combo consistent w/ those in slide 2022-05-02 17:29:29 -04:00
John Colvin 91aeccb2ae ui: Use normal font size outside of grids in slide 2022-05-02 17:29:29 -04:00
John Colvin 82864a609d ui: Make '|' separator consistent in slide status bars (upper/lower) 2022-05-02 17:29:29 -04:00
John Colvin 828b1ca0c2 ui: Add '|' separators in slide status bar 2022-05-02 17:29:29 -04:00
John Colvin 6b740ece39 ui: Use common IValueConverter for last_trade in slide/combo wins 2022-05-02 17:29:29 -04:00
John Colvin 84f18288e0 fix: Fix typo 'call' -> 'put' in ComboReportOptionCellView 2022-05-02 17:29:29 -04:00
John Colvin cf9e5862ed fix: Invalidate 'measure' when ShowCallPut in combo opt cell
Bugs (fixed):
   * combo report does not show call/put when 'Show Call/Put' is checked
2022-05-02 17:29:29 -04:00
John Colvin 4ca2b5f4d2 fix: Add missing 'ExpirationTextConverter' resource in ComboReportView 2022-05-02 17:29:29 -04:00
John Colvin da2894512d fix: Fix typo 'ComboReport' -> 'ComboReportView' 2022-05-02 17:29:29 -04:00
John Colvin 55e9487203 fix: Sync strikes and exps in combo on_data callback 2022-05-02 17:29:29 -04:00
John Colvin 19fb08e7ff fix: Add nullcheck in TradeLogRow ctr 2022-05-02 17:29:29 -04:00
John Colvin 193b1025ad style: Clean up ReportDaemon 2022-05-02 17:29:29 -04:00
John Colvin 8fa2a925cd refactor: Use ToggleCommand/SparkMenuItemToggleModel in slide win 2022-05-02 17:29:29 -04:00
John Colvin 526daa9647 ui: Use 'candidate' icon for 'Use Candidate Vol' menu item 2022-05-02 12:29:03 -04:00
John Colvin 43bcc9fe02 Add 'candidate' icon
Even though not in use atm, it was hard to parse out the individual
candidate from the svg, and might come in handy down the road.  Seems worth
keeping
2022-05-02 12:29:03 -04:00
John Colvin 51d6066420 fix: Add nullcheck in get_vs_price_map 2022-05-02 12:29:03 -04:00
John Colvin 0b11b83eb5 ui: Refine slide win
* dock account/risk terms to the left
2022-05-02 12:29:03 -04:00
John Colvin a53dfd14b1 ui: Refine combo win
* make call/put toggle a spark menu item (in the toolbar)
* dock account/risk terms to the left
* hide account/risk terms labels (show them as tooltips instead)
2022-05-02 12:29:02 -04:00
John Colvin cc0380d8f1 Add ToggleCommand type and related infrastructure 2022-05-02 12:29:02 -04:00
John Colvin 0a01d22e72 refactor: Rename 'UseCandidateVol' icon -> 'vol_curve' 2022-05-02 12:29:02 -04:00
John Colvin e9f1c72198 refactor: Refine 'create_checked_icon' code/logic
Clean up code a bit, and add some parameters to custom fit/position the
check mark with any given Drawing
2022-05-02 12:29:02 -04:00
John Colvin 14af8823ed refactor: Rename SparkCommandVM -> SparkMenuItemVM
Also move to 'ViewModels' dir
2022-05-02 12:29:02 -04:00
John Colvin 5900ce7d12 Fix windows build after moving FileUtils to lib 2022-05-02 12:29:02 -04:00
John Colvin 33e0a6bb46 Generate new keycodes for default config
These won't expire until 2032
2022-05-02 12:29:02 -04:00
John Colvin ca3bc5059e Read public key from config (for login/auth) 2022-05-02 12:29:02 -04:00
John Colvin bd108dfe35 cli (server): Add key-code subcommand to sparkd 2022-05-02 12:29:02 -04:00
John Colvin 8a96c7441e refactor: Clean up KeyCode 2022-05-02 12:29:01 -04:00
John Colvin 4eea3194fd Remove unused args from key-code subcmds 2022-05-02 12:29:01 -04:00
John Colvin dace332ac5 refactor: Move FileUtils into lib 2022-05-02 12:29:01 -04:00
John Colvin af816bb905 fix: Don't cast numeric types via boxing
This is illegal
2022-05-02 12:29:01 -04:00
John Colvin 195c24ffef refactor: Move SingleValueList to own file 2022-05-02 12:29:01 -04:00
John Colvin 92ad17aa19 fix: Save slide report before closing settings dialog
Bugs (fixed):
   * Slide report configuration doesn't save on OK click (does save on Apply
   click though)
2022-05-02 12:29:01 -04:00
John Colvin eabc4bee4c fix: Save combo report before closing settings dialog
Bugs (fixed):
   * Combo report configuration doesn't save on OK click (does save on Apply
   click though)
2022-05-02 12:29:01 -04:00
John Colvin 0ed9142cf0 test: Add HierarchicalDictionaryTest 2022-05-02 12:29:01 -04:00
John Colvin 1639683b43 fix: Set _value_count to 0 when HierarchicalDictionary is Cleared 2022-05-02 12:29:01 -04:00
John Colvin 05afb08c5d fix: Ensure HierarchicalDictionary nodes in sync w/ parent data 2022-05-02 12:29:01 -04:00
John Colvin c674e44c60 refactor: Enable nullable in EnumerableExtensions 2022-05-02 12:29:00 -04:00
John Colvin e104c78471 fix (preemptive): Fix typo in Sum ext
This fix is preemptive only bc this fn isn't referenced atm
2022-05-02 12:29:00 -04:00
John Colvin 3d8ec63bd7 ui: Condense text/controls in top of Slide win 2022-05-02 12:29:00 -04:00
John Colvin 99670c9d28 ui: Move last update time down to status bar in Slide win 2022-05-02 12:29:00 -04:00
John Colvin 56126e19a7 refactor: Clean up SlideReportView.xaml.cs 2022-05-02 12:29:00 -04:00
John Colvin 05e8363504 ui: Change 'Use Candidate Vol' icon to look sort of like vol-curve 2022-05-02 12:29:00 -04:00
John Colvin 884741062b ui: Add expand/collapse toggle menu item to Combo win 2022-05-02 12:29:00 -04:00
John Colvin 63c77966fa ui: Add menu-orientation menu-item to Slide win 2022-05-02 12:29:00 -04:00
John Colvin 31745d9f0d ui: Add menu-orientation menu-item to Combo win 2022-05-02 12:29:00 -04:00
John Colvin 78897ed608 refactor: Clean up SparkMenu
* use visual states instead of triggers for mouse-state-transition animation
* use new lang feats
* run formatter
2022-05-02 12:29:00 -04:00
John Colvin 5712bcdc57 Add PressedAnimationDuration prop to MouseStateDefinition
This provides a way to ensure that 'Pressed' animations, which takes a
non-zero amt of time, always run to completion (before animation for the
next state begins)
2022-05-02 12:28:59 -04:00
John Colvin 8e0a027584 style: Add documentation to ProjectToVector ext 2022-05-02 12:28:59 -04:00
John Colvin 12f88b5303 test: Add unit test for ProjectToVector ext 2022-05-02 12:28:59 -04:00
John Colvin b119cad8a9 ui: Remove 'Focus' animation from SparkMenuButton
Not sure why this was here in the first place..it's identical to the
MouseOver animation
2022-05-02 12:28:59 -04:00
John Colvin f30210e4e1 refactor: Move SparkMenu style/xaml to own file 2022-05-02 12:28:59 -04:00
John Colvin a8d6a104c3 refactor: Clean up OptionDriverPriceMap 2022-05-02 12:28:59 -04:00
John Colvin 13df0c8638 Spruce up AnalyticsShellModuleView 2022-05-02 12:28:59 -04:00
John Colvin fb70aa6514 fix (ui): Set combo report settings dialog title to string literal
Previously, it was bound to the report-name.  However, the binding was broken.
Furthermore it doesn't seem appropriate to bind the title to the name since the
user can edit the name in the settings dialog
2022-05-02 12:28:59 -04:00
John Colvin 37fd1d424e refactor: Rename (SlideReportSettings)View -> Dialog
This is more consistent with our name conventions, and dialog is more
precise description of the type
2022-05-02 12:28:59 -04:00
John Colvin bdbbcb05dc ui: Animate AnalyticsShellModule window-section expand/collapse 2022-05-02 12:28:59 -04:00
John Colvin 9cd5d0890f ui: Add large-flat button style 2022-05-02 12:28:59 -04:00
John Colvin 7b1fa849ef fix (preemptive): Curry 'Member' to DataContextChanged callback
Bugs (fixed):
   * [preemptive] potential InvalidCastException in
   RadioButtonGroupManager.DataContextChanged callback
2022-05-02 12:28:59 -04:00
John Colvin a8b5cf81ee fix (ui): Set combo report settings dialog title to string literal
Previously, it was bound to the report-name.  However, the binding was
broken; furthermore it doesn't seem appropriate to bind to the name
since the user can edit the name in the settings dialog
2022-05-02 12:28:58 -04:00
John Colvin bc62d4b359 refactor: Rename (ComboReportSettings)View -> Dialog
This is more consistent with our naming conventions, and 'dialog' is a
more precise description of this type.
2022-05-02 12:28:58 -04:00
John Colvin 4413580212 feat: Support modifying combo report 'name' after it is created
The csharp vm infrastructure was already in place, so this was just a matter of
adding the 'name' field to the settings view
2022-05-02 12:28:58 -04:00
John Colvin 8b653ef133 feat: Add volume col to TimeAndSales 2022-05-02 12:28:58 -04:00
John Colvin b1f8ac7e22 refactor: Make Optional<T> a struct
It's a trivial, readonly type, so struct seems more appropriate than class

Bugs (fixed):
   * [preemptive] greeks_tuple param potential null-ref exception in TradeInfo
   'with' ext
2022-05-02 12:28:58 -04:00
John Colvin a11c23d718 refactor: Enable nullable in TimeAndSales(Filter)Settings 2022-05-02 12:28:58 -04:00
John Colvin 9feceb9fdb fix: Create new instance of ContextMenu on each open
Bugs (fixed):
   * the volsurface grid context menu items' col/super header names don't stay
   in sync with clicked cell (the names never change once the menu item becomes
   visible for the first time)
2022-05-02 12:28:58 -04:00
John Colvin bad6464fe9 refactor: Clean up VolSurfaceRowContextMenuVM
* use new lang feats
* run formatter
2022-05-02 12:28:58 -04:00
John Colvin a6007ca362 refactor: Sync symbols in vs row context menu when vis-exps changes
Also, rename SymbolFilter -> SymbolItemVM
2022-05-02 12:28:58 -04:00
John Colvin 05348b01ae refactor: Clean up VolSurfaceRowVM
* use new lang feats
* run formatter
2022-05-02 12:28:58 -04:00
John Colvin abfabe3e21 Remove unused file VolSurfaceRowControl.cs 2022-05-02 12:28:58 -04:00
John Colvin 83e0da446a refactor: Rename VolSurfaceRowContext -> VolSurfaceRowVM 2022-05-02 12:28:58 -04:00
John Colvin 85a48e71d1 refactor: Move vs row context menu vm to own file & unnest class 2022-05-02 12:28:57 -04:00
John Colvin 0671117660 refactor: Move sync_with ext to ListExtensions 2022-05-02 12:28:57 -04:00
John Colvin 654c5b3074 refactor: Rename 'command' members 'cmd' in VolSurfaceRowContext 2022-05-02 12:28:57 -04:00
John Colvin aee5e54c14 refactor: Clean up VolSurfaceVM
* use new lang feats
* rename 'command' members 'cmd'
* sort members
2022-05-02 12:28:57 -04:00
John Colvin e5df037992 refactor: Remove redundant LastOrDefault ext fn 2022-05-02 12:28:57 -04:00
John Colvin 06b9586eb6 refactor: Consolidate tick up/down fn pairs into singular tick fns
With 'is_up' params
2022-05-02 12:28:57 -04:00
John Colvin 79716dfdba refactor: Add NotNullWhen attrs to tick up/down out params 2022-05-02 12:28:57 -04:00
John Colvin 02b6b5d078 fix: Handle nan qty gracefully on ladder qty button click
Just set the value to that of the clicked button (since you can't add
anything to NaN)
2022-05-02 12:28:57 -04:00
John Colvin 403e8d2947 ui: Change TickUpDownNullable control to reset null -> 0 on tick click 2022-05-02 12:28:57 -04:00
John Colvin 25e9c37987 refactor: Change props to generic T in TickUpDownNullableNumeric
Accidentally left several members defined as type double (this
now-generic class was refactored from TickUpDownNullableDouble)
2022-05-02 12:28:57 -04:00
John Colvin 99b58cf2bf refactor: Clean up LadderVM
* use new lang feats
* sort members
* run formatter
2022-05-02 12:28:56 -04:00
John Colvin 78155cfbdf refactor: Clean up LadderOrderVM
* use new lang feats
* sort members
* run formatter
2022-05-02 12:28:56 -04:00
John Colvin 1ba980d69f refactor: Accept tuples with non-uniform types in 'Sum' ext 2022-05-02 12:28:56 -04:00
John Colvin ef155aaedf Remove redundant bootstrapping code from TableUpdateDemuxer 2022-05-02 12:28:56 -04:00
John Colvin 22c4b528cb fix: Actually propagate updates to Subject nodes in TableUpdateDemuxer
Bugs (fixed):
   * Working orders are not showing in ladder
2022-05-02 12:28:56 -04:00
John Colvin fd71c6ac7a Set ShowDecimalPart to false in default qty display settings 2022-05-02 12:28:56 -04:00
John Colvin 019fa134cb fix: Use valid defaults for price/qty display in SecurityMD 2022-05-02 12:28:56 -04:00
John Colvin 4a40bd3364 refactor: Move SecurityDataHelper to spark_api proj 2022-05-02 12:28:56 -04:00
John Colvin 68229b2474 build (server): Update CMakeDeps 2022-05-02 12:28:56 -04:00
John Colvin 8727ed6ccd Upgrade server to dotnet-sdk 6
* upgraded externals to install dotnet-sdk-6.0 in docker
* rewound the sdk version specified in global.json to 6.0.200 (latest
available in the apt repository)
* updated some fs code that wasn't backwards compatible (namely the
builtin 'TryParse' methods)
2022-05-02 12:28:56 -04:00
John Colvin 8ee3d5b8ad web: Add tsconfig for clang release build
Not sure why this file was absent in the first place, as similar
tsconfig files were already present for clang debug, and gcc
debug/release
2022-05-02 12:28:55 -04:00
John Colvin 98ee43aa27 ui: Add spark menu items to toggle auto-copy-rolls/rates 2022-05-02 12:28:55 -04:00
John Colvin 92291e3f9f refactor: Clean up AnalyticsParametersManager
* replace ThreadedBlackboard w/ IBus
* use new lang feats
* run formatter
2022-05-02 12:28:55 -04:00
John Colvin 1abb41a0d5 ui: Change sec-type abbrev to be all caps 2022-05-02 12:28:55 -04:00
John Colvin 0993195f03 fix: Use CollectionViewSource to workaround wpf bug
Bugs (fixed):
   * Some dropdowns in exp params grid are empty
2022-05-02 12:28:55 -04:00
John Colvin c2a7c6f994 fix: Set result to null if conversion to nullable<T> fails
Was setting the result to default(T) before

Bugs (fixed):
   * Various exceptions stem from failed conversions to nullable types
   when the underlying type doesn't have a valid default state.  For
   example, default instances of immutable protobufs throw exceptions in
   property accessors for reference type members.
2022-05-02 12:28:55 -04:00
John Colvin 48900cf5a0 ui: Use BTSColors.input_dirty_border in exp params
This makes the 'dirty' color consistent with the rest of the system (was
using hardcoded Red before)
2022-05-02 12:28:55 -04:00
John Colvin 57fbb36808 feat: Add TimeWeightedInterpolated driver to analytics exp params 2022-05-02 12:28:55 -04:00
John Colvin 5c45384c34 refactor: Clean up AnalyticsExpirationParametersRowVM
* use new lang feats
* run formatter
2022-05-02 12:28:55 -04:00
John Colvin f9aa162e2a refactor: Clean up AnalyticsExpirationParametersVM
* use new lang feats
* run formatter
2022-05-02 12:28:55 -04:00
John Colvin 013d17c386 refactor: Enable nullable in AnalyticsExpirationParametersView.xaml.cs 2022-05-02 12:28:55 -04:00
John Colvin ad250c3883 fix: Include sec-type str in ExpirationTextConverter
Bugs (fixed):
   * ExpirationTextConverter.Convert doesn't include the sec-type part
   when 'ShowType' is true
2022-05-02 12:28:55 -04:00
Taha Afzal 2c9e0012e2 Cleaning up VolSurfaceRiskCalculator vs VolSurfaceSlideCalculator 2022-04-29 12:57:35 -04:00
Taha Afzal 2516f23e37 TC2 gets its list of symbols form the settings the rightway now 2022-04-29 12:43:34 -04:00
Taha Afzal d3a7bd48c2 Account setting in Slide is being respected now 2022-04-28 18:37:07 -04:00
Taha Afzal 4aeb7490e3 Slide calculates now if the caculation mode is set for Live Theo or Position update 2022-04-28 17:11:03 -04:00
Taha Afzal 265beef715 Slide is working (showing data, not verified the data though 2022-04-27 19:34:13 -04:00
Taha Afzal a58bf83a9a Added Combo computing code (temporarily brought old VoLSurfaceRiskCalculator back 2022-04-25 17:56:24 -04:00
John Colvin 9da1a4a2de fix: Remove CharSet.Unicode' from 'Logger_log' DLLImport attr
Bugs (fixed):
   * csharp logs only include the first char of the log message

Omnisharp recommended this be specified in the attribute after upgrading to
dotnet 6.  They were wrong.
2022-04-20 12:48:37 -04:00
John Colvin 8a98e38e73 Include opts (and futs) in manual fills sec popup 2022-04-20 02:42:35 -04:00
John Colvin 3044f4a0b1 ui: Sort accounts in dropdown in slide settings dialog 2022-04-20 02:12:14 -04:00
John Colvin 5104ae1742 ui: Set ComboReportWindow.MinWidth to 500
The default width was too narrow, and caused some labels to overlap
2022-04-20 01:47:47 -04:00
John Colvin 987ec14da2 Remove redundant call to _validate in combo conf vm 2022-04-20 01:39:52 -04:00
John Colvin 24c6e0df97 fix: Refresh combo report-result prop when risk-terms-name changes 2022-04-20 01:39:21 -04:00
John Colvin 23d5d18b28 fix: Set report.Id when saving combo report
Bugs (fixed):
   * When ok/apply is clicked in combo report settings, a new report is created
   with those params, instead of modifying the existing report
2022-04-20 01:38:22 -04:00
John Colvin 0a38c241af refactor: Rename ComboVM -> ComboReportVM 2022-04-20 00:36:53 -04:00
John Colvin 5b0d79ad17 refactor: Move ObservantAsyncCommand into ns Spark.ViewModel.Commands 2022-04-19 11:42:44 -04:00
John Colvin 833187559d refactor: Move AsyncCommand to ns Spark.ViewModel.Commands 2022-04-19 11:42:44 -04:00
John Colvin 527066e4c8 refactor: Move IRaiseCanExecuteChangedCommand to ns Spark.ViewModel.Commands 2022-04-19 11:42:44 -04:00
John Colvin bad30a49bf Open options-view with security-picker
TODO: translate the SecurityCriteria into NMSheetsSettings so the
selected criteria is actually used in the window
2022-04-19 11:42:44 -04:00
John Colvin 24f40dd652 ui: Hide strikes/callput fields in contract-picker 2022-04-19 11:42:44 -04:00
John Colvin dce61183dd fix (preemptive): Unhook callbacks when contract-picker controller disposed 2022-04-19 11:42:44 -04:00
John Colvin aeb81a9e86 fix (preemptive): Init contract-picker controller when datacontext changes 2022-04-19 11:42:44 -04:00
John Colvin 81aea15988 ui: Use qty display settings in fills 2022-04-19 11:42:44 -04:00
John Colvin 3e393208ab ui: Use qty display settings in orderbook 2022-04-19 11:42:44 -04:00
John Colvin 0674accd05 Set initial qty to NaN (not 0) in ladder
This makes the initial state consistent with the state after clicking
'Clear'
2022-04-19 11:42:44 -04:00
John Colvin 0f0d8df572 fix: Set init val through display-translator in SizeCalculator
The init val was being passed to the erroneous `UserProperty<T?> _value` field,
which should have been deleted when the _display_translator was introduced.

Bugs (fixed):
   * the ladder-view's initial size field is null when
2022-04-19 11:42:44 -04:00
John Colvin 0afd06be9c feat: Support double qty input in order ticket 2022-04-19 11:42:44 -04:00
John Colvin 1539bfa8b1 feat: Support double quantity input in Ladder 2022-04-19 11:42:43 -04:00
John Colvin a2336be143 fix: Check if _settings is null in LadderGridHost._refresh_prices
Bugs (fixed):
   * NullReferenceException is thrown when the right-panel-ladder (in
   OrderBook) is opened with no selected rows
2022-04-19 11:42:43 -04:00
John Colvin 7d65befc7e refactor: Overload detect_property_changes w/ eq comp params 2022-04-19 11:42:43 -04:00
John Colvin 916b28bc16 refactor: Clean up LadderVMContainer 2022-04-19 11:42:43 -04:00
John Colvin fb3447a6b4 refactor: Consolidate TickUpDownNullable classes into generic impl 2022-04-19 11:42:43 -04:00
John Colvin 2fa9b2e0e5 refactor: Rename TickUp/DownParameter TickUp/DownCommandParameter 2022-04-19 11:42:43 -04:00
John Colvin a66d3fb28a refactor: Return bool indicating whether object was disposed 2022-04-19 11:42:43 -04:00
John Colvin 6be017d35b fix: Make new instances of arrow icons instead of sharing
Bugs (fixed):
   * 'Freezable cannot be frozen' exception thrown when opening
   multiple windows (on diff threads) that use the same arrow icons
2022-04-19 11:42:43 -04:00
John Colvin ef24e5164f refactor: Change uint qty members to doubles 2022-04-19 11:42:43 -04:00
John Colvin a7f36b2361 refactor: Support generic numerics in tick-utils 2022-04-19 11:42:43 -04:00
John Colvin 3d404002a0 refactor: Make QuantityConversionData generic for numeric T 2022-04-19 11:42:43 -04:00
John Colvin 1922a1b49c refactor: Make MathUtils/NumericExtensions generic 2022-04-19 11:42:43 -04:00
John Colvin ca4ec7025c Add price/quantity display config to SecurityMD 2022-04-19 11:42:43 -04:00
John Colvin 7dcfa709d5 Add SecurityMetadata (proto3) config
Immediate Purpose:
   * Add security-based config for 'unit-quantity'
2022-04-19 11:42:43 -04:00
John Colvin aa254142e8 Add client-side support for proto3 config 2022-04-19 11:42:42 -04:00
John Colvin b00b12bed2 refactor: Clean up MDSource/Daemon and deps 2022-04-19 11:42:42 -04:00
John Colvin dd7168a687 Add SecurityMetadata pbuf to client build 2022-04-19 11:42:42 -04:00
John Colvin 97b665733a Add SecurityCriteria pbuf type to client build 2022-04-19 11:42:42 -04:00
John Colvin 4a6d3e3042 Add bts/api/domain to proto search path for config 2022-04-19 11:42:42 -04:00
John Colvin f65cf43e21 refactor: Rename bts.api.domain.SecurityType.INDEX -> SPOT 2022-04-19 11:42:42 -04:00
John Colvin f971d4db51 Add SYNTHETIC to bts.api.domain.SecurityType 2022-04-19 11:42:42 -04:00
John Colvin 8cd79c0372 Add BTS and SIM to bts.api.domain.Venue 2022-04-19 11:42:42 -04:00
John Colvin 9bc346e84a refactor: Clean up SecurityCriteria
* move SecurityCriteriaClause into own file
* convert fields to props
* sort members
* use new lang feats
* run formatters
2022-04-19 11:42:42 -04:00
John Colvin 88d2e1756f refactor: Rename config.cs -> Configuration.cs 2022-04-19 11:42:42 -04:00
John Colvin dc09c45330 refactor: Clean up config.cs
* use new lang feats
* specify CharSet.Unicode in DLLImports (avoids warning ca2101)
* sort members
* run formatter
2022-04-19 11:42:42 -04:00
John Colvin 47e5b57789 style: Clean up SecurityMD
* sort members
* use new lang feats
* run formatter
2022-04-19 11:42:42 -04:00
John Colvin c1ad8ed4b2 style: Clean up AnalyticsService.proto 2022-04-19 11:42:42 -04:00
John Colvin 3589b5c9a8 build: Upgrade MEF pkgs in spark proj
Also remove unneccessary pkg 'Microsoft.Extensions.DependencyInjection'
2022-04-19 11:42:42 -04:00
John Colvin fbaf15ad34 fix: Export shared inst for IWindowManager/Interop
Bugs (fixed):
   * 2 WindowManager instances are created on startup!  This causes many
   problems (for ex, 'IShellWindow.thread_init' is called twice for each
   shell window)
2022-04-19 11:42:42 -04:00
John Colvin ee1d02991c feat: Port combo report over from edge 2022-04-19 11:42:42 -04:00
John Colvin 2450cb028e Fix BTSOxyGraph background binding 2022-04-19 11:42:42 -04:00
John Colvin ec1182f059 Impl IEquatable in SparkTag
This is a pre-emptive fix.  Without it, we are susceptible to potential hash
collision bugs in the bus
2022-04-19 11:42:41 -04:00
John Colvin 7797d8255f fix: Avoid duplicate entries in cpp list 2022-04-19 11:42:41 -04:00
John Colvin a4780ecac7 refactor: Make 'within_range' param order consistent 2022-04-19 11:42:41 -04:00
John Colvin 32643990ee refactor: Use generic math in MathUtils/NumericExtensions 2022-04-19 11:42:41 -04:00
John Colvin 5746e6267a Check equality in BoundColumn prop setters
Only call 'RaisePropertyChanged' when value actually changes
2022-04-19 11:42:41 -04:00
John Colvin 501ec81405 build: EnablePreviewFeatures for cs build
Namely, to enable generic math to allow for generic use of numeric
binary operators
2022-04-19 11:42:41 -04:00
John Colvin 714f4fe995 refactor: Drop 'Single' in SingleComboReportCalculator 2022-04-19 11:42:41 -04:00
John Colvin ead71a5618 style: Move ComboFuture/StrikeData into own files 2022-04-19 11:42:41 -04:00
John Colvin eaf6e4ba28 refactor: Clean up VolSurfaceUtilityFunctions
* use new lang feats
* remove redundant ported functionality (refactor w/ impls in spark)
* run formatter
2022-04-19 11:42:41 -04:00
John Colvin bef2c9310e Add 'Fill' list ext fn 2022-04-19 11:42:41 -04:00
John Colvin 7b3e0d4a59 refactor: Clean up SecurityTuple/Expiration/Strike
* use new lang feats
* sort members
* run formatter
2022-04-19 11:42:41 -04:00
John Colvin ea0705e7e4 fix: Avoid dupl keys when stripping exch from SecurityExpiration 2022-04-19 11:42:41 -04:00
John Colvin 7b9310f595 refactor: Repl IDict w/ IReadOnlyDicts in vs risk calc 2022-04-19 11:42:41 -04:00
John Colvin a31f775de8 refactor: Simplify change_vol_dervs_to_percentages 2022-04-19 11:42:41 -04:00
John Colvin f061630789 refactor: Clean up VolSurfaceRiskCalculator
* Use new lang feats
2022-04-19 11:42:41 -04:00
John Colvin 5d442125b0 refactor: Use switch case for is_delta_greek impl 2022-04-19 11:42:41 -04:00
John Colvin e600f444f8 refactor: Clean up Slide/VolSurfaceRisk calcs
* Gather related 'out params' into new SecurityPositionData struct
* Break up long compute_and_fire fn in SlideReportCalculator into several fns
* Use new log_op fn to eliminate messy timer code sections
* Run formatter
2022-04-19 11:42:41 -04:00
John Colvin a8ae4d6655 Add create, append, to_comparer fns for ComparerBuilder 2022-04-19 11:42:41 -04:00
John Colvin a885fa7065 Add LoggerExtensions to record (time) ops 2022-04-19 11:42:41 -04:00
John Colvin 65665dc384 Add HierarchicalDictionary
A useful abstraction for nested dictionaries
2022-04-19 11:42:40 -04:00
John Colvin a8992edf88 fix: Check report type when converting to Report pbuf 2022-04-19 11:42:40 -04:00
John Colvin 1b7dd28c2f fix: Use key/value comparer args when creating SetMap
This is a pre-emptive fix, as this fn isn't currently referenced
2022-04-19 11:42:40 -04:00
John Colvin ae692432a2 fix: Use sec type arg when converting vsexp to securityexp
Bugs (fixed):
   * duplicate items in slide report expirations dropdown

In code recently ported from edge, the security type was [assumed to be]
implied by the symbol's capitalization: futures begin with upper-case letters,
while options begin with lower-case.  This assumption has become unreliable (at
deribit, both futures and options are all upper-case).
2022-04-19 11:42:40 -04:00
John Colvin c779b31a90 refactor: Clean up [csharp] co2 classes
* Move all [non-nested] classes/structs into own files
* Sort members
* Fix naming convention violations
* Use new lang feats
* Run formatter
2022-04-19 11:42:40 -04:00
John Colvin cb4bf8f5f4 Remove unused class TimeAndSalesModel 2022-04-19 11:42:40 -04:00
John Colvin 96cd807720 Add fake slide report data 2022-04-19 11:42:40 -04:00
John Colvin 07c3150d2a refactor: Change abstract TradeLogRow class to interface 2022-04-19 11:42:40 -04:00
John Colvin c66a405e6d refactor: Enable nullable (lang feat) on some Slide files 2022-04-19 11:42:40 -04:00
John Colvin 0558381bcb Add DataTemplates ResourceDictionary to TimeFilterControl
So callers aren't required to include it themselves
2022-04-19 11:42:40 -04:00
John Colvin 1db47684b7 refactor: Remove redundant ImmutableWrapper for list 2022-04-19 11:42:40 -04:00
John Colvin e16abd2e8b Check AdornerLayer not null when adding drag adorner
Bugs (fixed):
   * Opening slide report settings dialog causes crash
2022-04-19 11:42:40 -04:00
John Colvin f7adc84f0e feat: Port slide report over from edge 2022-04-19 11:42:40 -04:00
John Colvin 3acd51b247 refactor: Replace non pbuf ReportParameters with pbuf Report 2022-04-19 11:42:40 -04:00
John Colvin 6caab9c017 refactor: Make tags create/activate reports type-agnostic 2022-04-19 11:42:40 -04:00
John Colvin 97c61d2a4f refactor: Rename SingleSlideReportCalculator SlideReportCalculator 2022-04-19 11:42:40 -04:00
John Colvin 4f6a0061fe refactor: Clean up ObservableDemuxer
* Move to spark_core
* Split classes into sep files
* Use new lang feats
* Run formatter
2022-04-19 11:42:40 -04:00
John Colvin 5b201069e8 Add Bootstrap ext fn for IObservables 2022-04-19 11:42:39 -04:00
John Colvin 8b5d79847f Add 'Select' ext fns for Update/TableUpdate 2022-04-19 11:42:39 -04:00
John Colvin 2d112a86af refactor: Remove LegacyTableUpdate (repl w/ TableUpdate) 2022-04-19 11:42:39 -04:00
John Colvin 8806a62af7 refactor: Clean up ReflectionHelper/ObjectSnapshot
* Consolidate as much code as possible in ReflectionHelper (spark_core)
* Sort members
* Run formatter
2022-04-19 11:42:39 -04:00
John Colvin 01748ee847 Remove ExpirationTemplate from DataTemplates.xaml
It isn't general purpose enough to justify its presence in this global
resource file
2022-04-19 11:42:39 -04:00
John Colvin 6f1fb24a31 refactor: Move ExpTextConverter into own file
Also rename it "ExpirationTextConverter"
2022-04-19 11:42:39 -04:00
John Colvin c30459115e Post accounts-map on the bus 2022-04-19 11:42:39 -04:00
John Colvin 7cdfcbf6dc Support changes to icon in SparkMenuItem 2022-04-19 11:42:39 -04:00
John Colvin acf140e670 Add ObservableValue to spark_core 2022-04-19 11:42:39 -04:00
John Colvin df4a18e887 refactor: Clean up ComparerBuilder
* Implement IList<IComparer<T>>
* Use new lang feats
* Run formatter
2022-04-19 11:42:39 -04:00
John Colvin dc3836065a refactor: Move pbuf clone exception handling into 'try_clone' 2022-04-19 11:42:39 -04:00
John Colvin 3df7ab194c refactor: Clean up ProtobufSerializationHelper
* Use new lang feats
* Rename clone_protobuf -> clone
* Run formatter
2022-04-19 11:42:39 -04:00
John Colvin c0af8460a2 refactor: Move ProtobufSerializationHelper into spark_core 2022-04-19 11:42:39 -04:00
John Colvin 85d94a84a8 Add Chevron icons (right and down) 2022-04-19 11:42:39 -04:00
John Colvin 6ad6a361f9 Execute async command in try/catch
Purpose: treat both completed and canceled tasks as "finished."

Previously, the AsyncCommand waited endlessly for "canceled" tasks to finish.
As a result, if the command disallowed concurrent execution, the 'CanExecute'
flag would never be flipped back to true, and any buttons associated with that
command would be permanently disabled.
2022-04-19 11:42:39 -04:00
John Colvin 2a5dcab60f refactor: Move UserSymbol into own file 2022-04-19 11:42:39 -04:00
John Colvin 02b97d594f Add ReportExtensions 2022-04-19 11:42:38 -04:00
John Colvin 5e1cac251b fix: Actually copy untracked files in git-save.py 2022-04-19 11:42:38 -04:00
John Colvin 3639638bf2 refactor: Clean up AnalyticsShellModule a bit 2022-04-19 11:42:38 -04:00
John Colvin e255e054d4 refactor: Split analytics module/viewmodel into sep classes 2022-04-19 11:42:38 -04:00
John Colvin 8c9d8e7089 refactor: Move Commands dir into ViewModel 2022-04-19 11:42:38 -04:00
John Colvin f0e069d348 Add IProtobuf 2022-04-19 11:42:38 -04:00
John Colvin 4f32c8469e refactor: Clean up DateFormatter
* move DateFormat enum into sep file
* sort members
* use new lang feats
* run formatter
2022-04-19 11:42:38 -04:00
John Colvin b2679ecb60 Clean up old (recently ported) slide/report code 2022-04-19 11:42:38 -04:00
John Colvin e0537267a2 Add max_name_length field to EnumDescriptor 2022-04-19 11:42:38 -04:00
John Colvin 3440afd0d6 refactor: Split log-related classes into sep files 2022-04-19 11:42:38 -04:00
John Colvin cab65a0aaf refactor: Clean up TimeFilterVM
* Move ITimeFilterVM into separate file
* Use new lang feats
* Sort members
* Run formatter
2022-04-19 11:42:38 -04:00
John Colvin 910908b43e Add some handy Array utils 2022-04-19 11:42:38 -04:00
John Colvin cf1c1e6df1 refactor: Clean up ArrayUtils 2022-04-19 11:42:38 -04:00
John Colvin ff9b4f5b2f build: Upgrade dotnet core 5.0 -> 6.0 2022-04-19 11:42:38 -04:00
John Colvin 01899428e3 ui: Bind alignment props in ComboCheckBox template 2022-04-19 11:42:37 -04:00
John Colvin ff75ade140 fix build (client): Change 'uint' -> 'uint32_t'
Apparently the includes don't define 'uint' on windows
2022-04-19 11:34:28 -04:00
taha afzal 25d5f36645 Exchange positions are periodically published by OrderServices 2022-04-19 10:33:45 -04:00
Taha Afzal 5c5f042cac Logging in the Bus and threadedBlackboard classes adjusted 2022-04-18 13:16:16 -04:00
Taha Afzal 7da0b32838 SpreadSpec changes are handled rightaway (instead of being put on a timer) 2022-04-18 13:16:16 -04:00
Taha Afzal 389896be07 Retiring some SpreadBox superflous settings 2022-04-18 13:16:16 -04:00
Taha Afzal f55323afca SpreadBox settings cleaned up (partially) 2022-04-18 13:16:16 -04:00
Taha Afzal 0d5313d263 SpreadCalculationSynchronizer checks SpreadValue changes before posting them to the bus 2022-04-18 13:16:16 -04:00
Taha Afzal bc676b9731 Cleaning up the SpreadBox calculation code 2022-04-18 13:16:16 -04:00
Taha Afzal 0313a90196 Cleaned up SpreadManager 2022-04-18 13:16:16 -04:00
Taha Afzal fca1c62a55 Filtering expired contracts in the UI 2022-04-18 13:16:16 -04:00
Taha Afzal 2dcb0d6177 Fixed PriceControlGUI so that the price coule br overriden (locked) based on the consturctor arguments. For TC2 it does notallow overrides whereas for SpreadBoxes it does 2022-04-18 13:16:16 -04:00
Taha Afzal e2eea4bca7 Deleting unused SpreadBox spread types 2022-04-18 13:16:15 -04:00
Taha Afzal 9218184ef1 SpeadBox theo default formatting set to 4 dec places 2022-04-18 13:16:15 -04:00
Taha Afzal a9ec9e87be SpreadBox added 2022-04-18 13:16:15 -04:00
926 changed files with 53817 additions and 24691 deletions

No files matched your search

+2 -3
View File
@@ -1,5 +1,6 @@
nohup.out
build/
build/**
install/**
.build_proxy/
cmake-build-debug/
.cache/
@@ -40,8 +41,6 @@ trace_data/
.ionide/*
/.ignore
*.rej
/build
/build.*/*
.clangd/
*CMakeDeps.cmake
/sniper.ipynb
+13 -1
View File
@@ -13,6 +13,7 @@ set(SPARK_BIN "${EXTERNALS_ROOT}/bin")
set(SPARK_INCLUDE "${EXTERNALS_ROOT}/include")
set(SPARK_LIB "${EXTERNALS_ROOT}/lib/${CMAKE_BUILD_TYPE}")
set(BUILD_SDK OFF CACHE BOOL "Build the sdk")
set(BUILD_WEB ON CACHE BOOL "Build the web server")
include_directories(BEFORE SYSTEM ${SPARK_INCLUDE} ${EXTERNALS_ROOT}/include/zlib)
link_directories(${SPARK_LIB})
@@ -47,6 +48,11 @@ else()
# make sparkd look for libspark.so in its directory
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH ".")
set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install/${CMAKE_BUILD_TYPE}/sparkd")
add_compile_definitions(SPARK_ENABLE_CCAPI)
add_compile_definitions(CCAPI_ENABLE_SERVICE_MARKET_DATA)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_FTX)
add_compile_definitions(CCAPI_ENABLE_LOG_WARN)
# flags
set(
@@ -67,7 +73,9 @@ else()
# subdirs
add_subdirectory(src/server/sparkd)
add_subdirectory(src/lib)
add_subdirectory(src/web)
if (BUILD_WEB)
add_subdirectory(src/web)
endif()
add_subdirectory(doc/user)
if(BUILD_SDK)
add_subdirectory(src/sdk)
@@ -91,4 +99,8 @@ else()
DEPENDS sparkd data_files_dir)
add_custom_target(server_layout ALL DEPENDS ${CMAKE_BINARY_DIR}/server)
install(FILES "${CMAKE_SOURCE_DIR}/externals/linux/lib/${CMAKE_BUILD_TYPE}/libACE-5.7.5.so" DESTINATION bin)
install(FILES "${CMAKE_SOURCE_DIR}/externals/linux/lib/${CMAKE_BUILD_TYPE}/libOnixS.IceImpactMulticastPriceFeedHandlerCpp.so.3.16.0.0" DESTINATION bin)
install(FILES "${CMAKE_SOURCE_DIR}/externals/src/emumba/sparkd.lic" DESTINATION bin)
endif()
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,941 @@
{
"$schema": "vscode://schemas/color-theme",
"type": "dark",
"colors": {
"activityBar.background": "#111111",
"activityBar.border": "#111111",
"activityBar.foreground": "#888888",
"activityBarBadge.background": "#88cc44",
"activityBarBadge.foreground": "#222222",
"badge.background": "#88cc44",
"badge.foreground": "#222222",
"button.background": "#333333",
"button.foreground": "#888888",
"button.hoverBackground": "#222222",
"debugExceptionWidget.background": "#333333",
"debugExceptionWidget.border": "#222222",
"debugToolBar.background": "#111111",
"diffEditor.insertedTextBackground": "#ffdd440c",
"diffEditor.insertedTextBorder": "#ffdd44",
"diffEditor.removedTextBackground": "#88bbff0c",
"diffEditor.removedTextBorder": "#88bbff",
"dropdown.background": "#222222",
"dropdown.border": "#222222",
"dropdown.foreground": "#888888",
"editor.background": "#222222",
"editor.findMatchBackground": "#44446655",
"editor.findMatchHighlightBackground": "#444466aa",
"editor.foreground": "#ffffff",
"editor.hoverHighlightBackground": "#44446655",
"editor.inactiveSelectionBackground": "#44446655",
"editor.lineHighlightBackground": "#00000066",
"editor.lineHighlightBorder": "#00000000",
"editor.rangeHighlightBackground": "#333333",
"editor.selectionBackground": "#444466",
"editor.selectionHighlightBackground": "#44446655",
"editor.wordHighlightBackground": "#44446655",
"editor.wordHighlightStrongBackground": "#44446655",
"editorBracketMatch.background": "#222222",
"editorBracketMatch.border": "#666666",
"editorCodeLens.foreground": "#666666",
"editorCursor.foreground": "#ffffff",
"editorError.foreground": "#ee5500",
"editorGroup.border": "#111111",
"editorGroup.dropBackground": "#111111bb",
"editorGroupHeader.noTabsBackground": "#111111",
"editorGroupHeader.tabsBackground": "#111111",
"editorGroupHeader.tabsBorder": "#222222",
"editorGutter.addedBackground": "#ffdd44",
"editorGutter.background": "#222222",
"editorGutter.deletedBackground": "#88bbff",
"editorGutter.modifiedBackground": "#88bbff",
"editorHoverWidget.background": "#333333",
"editorHoverWidget.border": "#222222",
"editorIndentGuide.background": "#333333",
"editorLineNumber.foreground": "#555555",
"editorLink.activeForeground": "#bba0ff",
"editorMarkerNavigation.background": "#333333",
"editorMarkerNavigationError.background": "#88bbff",
"editorMarkerNavigationWarning.background": "#88bbff",
"editorOverviewRuler.addedForeground": "#ffdd44",
"editorOverviewRuler.border": "#222222",
"editorOverviewRuler.currentContentForeground": "#333333",
"editorOverviewRuler.deletedForeground": "#88bbff",
"editorOverviewRuler.errorForeground": "#88bbff",
"editorOverviewRuler.findMatchForeground": "#555555",
"editorOverviewRuler.incomingContentForeground": "#333333",
"editorOverviewRuler.infoForeground": "#bba0ff",
"editorOverviewRuler.modifiedForeground": "#88bbff",
"editorOverviewRuler.rangeHighlightForeground": "#333333",
"editorOverviewRuler.selectionHighlightForeground": "#555555",
"editorOverviewRuler.warningForeground": "#88bbff",
"editorOverviewRuler.wordHighlightForeground": "#333333",
"editorOverviewRuler.wordHighlightStrongForeground": "#555555",
"editorRuler.foreground": "#ffffff",
"editorSuggestWidget.background": "#333333",
"editorSuggestWidget.border": "#333333",
"editorSuggestWidget.foreground": "#888888",
"editorSuggestWidget.highlightForeground": "#ffffff",
"editorSuggestWidget.selectedBackground": "#666666",
"editorWarning.border": "#00000000",
"editorWarning.foreground": "#88bbff",
"editorWhitespace.foreground": "#333333",
"editorWidget.background": "#333333",
"editorWidget.border": "#333333",
"errorForeground": "#88bbff",
"extensionButton.prominentBackground": "#333333",
"extensionButton.prominentForeground": "#ffffff",
"extensionButton.prominentHoverBackground": "#555555",
"focusBorder": "#666666",
"foreground": "#ffffff",
"gitDecoration.modifiedResourceForeground": "#cccccc",
"gitDecoration.untrackedResourceForeground": "#cccccc",
"input.background": "#333333",
"input.border": "#333333",
"input.foreground": "#ffffff",
"input.placeholderForeground": "#555555",
"inputOption.activeBorder": "#555555",
"inputValidation.errorBackground": "#333333",
"inputValidation.errorBorder": "#88bbff",
"inputValidation.infoBackground": "#333333",
"inputValidation.infoBorder": "#bba0ff",
"inputValidation.warningBackground": "#333333",
"inputValidation.warningBorder": "#88bbff",
"list.activeSelectionBackground": "#111111",
"list.activeSelectionForeground": "#ffffff",
"list.dropBackground": "#111111bf",
"list.focusBackground": "#222222",
"list.focusForeground": "#ffffff",
"list.highlightForeground": "#ffffff",
"list.hoverBackground": "#333333",
"list.hoverForeground": "#ffffff",
"list.inactiveSelectionBackground": "#000000",
"list.inactiveSelectionForeground": "#ffffff",
"menu.background": "#333333",
"menu.foreground": "#ffffff",
"merge.border": "#222222",
"merge.currentContentBackground": "#333333",
"merge.currentHeaderBackground": "#555555",
"merge.incomingContentBackground": "#555555",
"merge.incomingHeaderBackground": "#666666",
"panel.background": "#111111",
"panel.border": "#111111",
"panelTitle.activeBorder": "#ffffff",
"panelTitle.activeForeground": "#ffffff",
"panelTitle.inactiveForeground": "#888888",
"peekView.border": "#222222",
"peekViewEditor.background": "#333333",
"peekViewEditor.matchHighlightBackground": "#555555",
"peekViewEditorGutter.background": "#333333",
"peekViewResult.background": "#333333",
"peekViewResult.fileForeground": "#888888",
"peekViewResult.lineForeground": "#888888",
"peekViewResult.matchHighlightBackground": "#555555",
"peekViewResult.selectionBackground": "#333333",
"peekViewResult.selectionForeground": "#ffffff",
"peekViewTitle.background": "#333333",
"peekViewTitleDescription.foreground": "#888888",
"peekViewTitleLabel.foreground": "#ffffff",
"pickerGroup.border": "#222222",
"pickerGroup.foreground": "#555555",
"progressBar.background": "#333333",
"scrollbar.shadow": "#191919",
"scrollbarSlider.activeBackground": "#ffffff12",
"scrollbarSlider.background": "#ffffff12",
"scrollbarSlider.hoverBackground": "#ffffff12",
"selection.background": "#2255aa",
"sideBar.background": "#111111",
"sideBar.border": "#111111",
"sideBar.foreground": "#888888",
"sideBarSectionHeader.background": "#111111",
"sideBarSectionHeader.foreground": "#666666",
"sideBarTitle.foreground": "#555555",
"statusBar.background": "#111111",
"statusBar.border": "#111111",
"statusBar.debuggingBackground": "#666666",
"statusBar.debuggingForeground": "#ffffff",
"statusBar.foreground": "#666666",
"statusBar.noFolderBackground": "#111111",
"statusBar.noFolderForeground": "#666666",
"statusBarItem.activeBackground": "#222222",
"statusBarItem.hoverBackground": "#222222",
"statusBarItem.prominentBackground": "#333333",
"statusBarItem.prominentHoverBackground": "#444444",
"tab.activeBackground": "#222222",
"tab.border": "#111111",
"tab.inactiveBackground": "#111111",
"tab.inactiveForeground": "#888888",
"tab.unfocusedActiveBorder": "#888888",
"tab.unfocusedActiveForeground": "#888888",
"tab.unfocusedInactiveForeground": "#888888",
"terminal.ansiBlack": "#333333",
"terminal.ansiBlue": "#88bbff",
"terminal.ansiBrightBlack": "#666666",
"terminal.ansiBrightBlue": "#88bbff",
"terminal.ansiBrightCyan": "#bba0ff",
"terminal.ansiBrightGreen": "#ffdd44",
"terminal.ansiBrightMagenta": "#88bbff",
"terminal.ansiBrightRed": "#88bbff",
"terminal.ansiBrightWhite": "#ffffff",
"terminal.ansiBrightYellow": "#88cc44",
"terminal.ansiCyan": "#bba0ff",
"terminal.ansiGreen": "#ffdd44",
"terminal.ansiMagenta": "#88bbff",
"terminal.ansiRed": "#88bbff",
"terminal.ansiWhite": "#ffffff",
"terminal.ansiYellow": "#88cc44",
"terminal.background": "#151515",
"terminal.foreground": "#ffffff",
"titleBar.activeBackground": "#111111",
"titleBar.activeForeground": "#888888",
"titleBar.inactiveBackground": "#111111",
"titleBar.inactiveForeground": "#555555",
"walkThrough.embeddedEditorBackground": "#111111",
"widget.shadow": "#111111",
//"activityBar.activeBorder": "#888888",
//"activityBar.dropBorder": "#888888",
//"activityBar.inactiveForeground": "#88888866",
//"banner.background": "#111111",
//"banner.foreground": "#ffffff",
//"banner.iconForeground": "#3794ff",
//"bookmarks.lineBackground": "#00000000",
//"bookmarks.lineBorder": "#00000000",
//"bookmarks.overviewRuler": "#157efb88",
//"breadcrumb.activeSelectionForeground": "#ffffff",
//"breadcrumb.background": "#222222",
//"breadcrumb.focusForeground": "#ffffff",
//"breadcrumb.foreground": "#ffffffcc",
//"breadcrumbPicker.background": "#333333",
//"button.secondaryBackground": "#3a3d41",
//"button.secondaryForeground": "#ffffff",
//"button.secondaryHoverBackground": "#45494e",
//"charts.blue": "#3794ff",
//"charts.foreground": "#ffffff",
//"charts.green": "#89d185",
//"charts.lines": "#ffffff80",
//"charts.orange": "#d18616",
//"charts.purple": "#b180d7",
//"charts.red": "#ee5500",
//"charts.yellow": "#88bbff",
//"checkbox.background": "#222222",
//"checkbox.border": "#222222",
//"checkbox.foreground": "#888888",
//"debugConsole.errorForeground": "#88bbff",
//"debugConsole.infoForeground": "#3794ff",
//"debugConsole.sourceForeground": "#ffffff",
//"debugConsole.warningForeground": "#88bbff",
//"debugConsoleInputIcon.foreground": "#ffffff",
//"debugIcon.breakpointCurrentStackframeForeground": "#ffcc00",
//"debugIcon.breakpointDisabledForeground": "#848484",
//"debugIcon.breakpointForeground": "#e51400",
//"debugIcon.breakpointStackframeForeground": "#89d185",
//"debugIcon.breakpointUnverifiedForeground": "#848484",
//"debugIcon.continueForeground": "#75beff",
//"debugIcon.disconnectForeground": "#f48771",
//"debugIcon.pauseForeground": "#75beff",
//"debugIcon.restartForeground": "#89d185",
//"debugIcon.startForeground": "#89d185",
//"debugIcon.stepBackForeground": "#75beff",
//"debugIcon.stepIntoForeground": "#75beff",
//"debugIcon.stepOutForeground": "#75beff",
//"debugIcon.stepOverForeground": "#75beff",
//"debugIcon.stopForeground": "#f48771",
//"debugTokenExpression.boolean": "#4e94ce",
//"debugTokenExpression.error": "#f48771",
//"debugTokenExpression.name": "#c586c0",
//"debugTokenExpression.number": "#b5cea8",
//"debugTokenExpression.string": "#ce9178",
//"debugTokenExpression.value": "#cccccc99",
//"debugView.exceptionLabelBackground": "#6c2022",
//"debugView.exceptionLabelForeground": "#ffffff",
//"debugView.stateLabelBackground": "#88888844",
//"debugView.stateLabelForeground": "#ffffff",
//"debugView.valueChangedHighlight": "#569cd6",
//"descriptionForeground": "#ffffffb3",
//"diffEditor.diagonalFill": "#cccccc33",
//"editor.findRangeHighlightBackground": "#3a3d4166",
//"editor.focusedStackFrameHighlightBackground": "#7abd7a4d",
//"editor.foldBackground": "#4444664d",
//"editor.inlineValuesBackground": "#ffc80033",
//"editor.inlineValuesForeground": "#ffffff80",
//"editor.linkedEditingBackground": "#ff00004d",
//"editor.snippetFinalTabstopHighlightBorder": "#525252",
//"editor.snippetTabstopHighlightBackground": "#7c7c7c4d",
//"editor.stackFrameHighlightBackground": "#ffff0033",
//"editor.symbolHighlightBackground": "#444466aa",
//"editorActiveLineNumber.foreground": "#c6c6c6",
//"editorBracketHighlight.foreground1": "#ffd700",
//"editorBracketHighlight.foreground2": "#da70d6",
//"editorBracketHighlight.foreground3": "#179fff",
//"editorBracketHighlight.foreground4": "#00000000",
//"editorBracketHighlight.foreground5": "#00000000",
//"editorBracketHighlight.foreground6": "#00000000",
//"editorBracketHighlight.unexpectedBracket.foreground": "#ff1212cc",
//"editorBracketPairGuide.activeBackground1": "#00000000",
//"editorBracketPairGuide.activeBackground2": "#00000000",
//"editorBracketPairGuide.activeBackground3": "#00000000",
//"editorBracketPairGuide.activeBackground4": "#00000000",
//"editorBracketPairGuide.activeBackground5": "#00000000",
//"editorBracketPairGuide.activeBackground6": "#00000000",
//"editorBracketPairGuide.background1": "#00000000",
//"editorBracketPairGuide.background2": "#00000000",
//"editorBracketPairGuide.background3": "#00000000",
//"editorBracketPairGuide.background4": "#00000000",
//"editorBracketPairGuide.background5": "#00000000",
//"editorBracketPairGuide.background6": "#00000000",
//"editorGhostText.foreground": "#ffffff56",
//"editorGutter.commentRangeForeground": "#c5c5c5",
//"editorGutter.foldingControlForeground": "#c5c5c5",
//"editorHint.foreground": "#eeeeeeb3",
//"editorHoverWidget.foreground": "#ffffff",
//"editorHoverWidget.highlightForeground": "#ffffff",
//"editorHoverWidget.statusBarBackground": "#3d3d3d",
//"editorIndentGuide.activeBackground": "#333333",
//"editorInfo.foreground": "#3794ff",
//"editorInlayHint.background": "#88cc4499",
//"editorInlayHint.foreground": "#222222cc",
//"editorInlayHint.parameterBackground": "#88cc4499",
//"editorInlayHint.parameterForeground": "#222222cc",
//"editorInlayHint.typeBackground": "#88cc4499",
//"editorInlayHint.typeForeground": "#222222cc",
//"editorLightBulb.foreground": "#ffcc00",
//"editorLightBulbAutoFix.foreground": "#75beff",
//"editorLineNumber.activeForeground": "#c6c6c6",
//"editorMarkerNavigationError.headerBackground": "#88bbff1a",
//"editorMarkerNavigationInfo.background": "#3794ff",
//"editorMarkerNavigationInfo.headerBackground": "#3794ff1a",
//"editorMarkerNavigationWarning.headerBackground": "#88bbff1a",
//"editorOverviewRuler.bracketMatchForeground": "#a0a0a0",
//"editorOverviewRuler.commonContentForeground": "#60606066",
//"editorOverviewRuler.unicodeForeground": "#d186167e",
//"editorPane.background": "#222222",
//"editorSuggestWidget.focusHighlightForeground": "#ffffff",
//"editorSuggestWidget.selectedForeground": "#ffffff",
//"editorSuggestWidgetStatus.foreground": "#88888880",
//"editorUnicodeHighlight.border": "#bd9b03",
//"editorUnnecessaryCode.opacity": "#000000aa",
//"editorWidget.foreground": "#ffffff",
//"extensionBadge.remoteBackground": "#88cc44",
//"extensionBadge.remoteForeground": "#222222",
//"extensionIcon.preReleaseForeground": "#1d9271",
//"extensionIcon.starForeground": "#ff8e00",
//"extensionIcon.verifiedForeground": "#3794ff",
//"gitDecoration.addedResourceForeground": "#81b88b",
//"gitDecoration.conflictingResourceForeground": "#e4676b",
//"gitDecoration.deletedResourceForeground": "#c74e39",
//"gitDecoration.ignoredResourceForeground": "#8c8c8c",
//"gitDecoration.renamedResourceForeground": "#73c991",
//"gitDecoration.stageDeletedResourceForeground": "#c74e39",
//"gitDecoration.stageModifiedResourceForeground": "#e2c08d",
//"gitDecoration.submoduleResourceForeground": "#8db9e2",
//"gitlens.closedAutolinkedIssueIconColor": "#a371f7",
//"gitlens.closedPullRequestIconColor": "#f85149",
//"gitlens.decorations.addedForegroundColor": "#81b88b",
//"gitlens.decorations.branchAheadForegroundColor": "#35b15e",
//"gitlens.decorations.branchBehindForegroundColor": "#b15e35",
//"gitlens.decorations.branchDivergedForegroundColor": "#d8af1b",
//"gitlens.decorations.branchMissingUpstreamForegroundColor": "#c74e39",
//"gitlens.decorations.branchUnpublishedForegroundColor": "#35b15e",
//"gitlens.decorations.branchUpToDateForegroundColor": "#888888",
//"gitlens.decorations.copiedForegroundColor": "#73c991",
//"gitlens.decorations.deletedForegroundColor": "#c74e39",
//"gitlens.decorations.ignoredForegroundColor": "#8c8c8c",
//"gitlens.decorations.modifiedForegroundColor": "#cccccc",
//"gitlens.decorations.renamedForegroundColor": "#73c991",
//"gitlens.decorations.untrackedForegroundColor": "#cccccc",
//"gitlens.gutterBackgroundColor": "#ffffff13",
//"gitlens.gutterForegroundColor": "#bebebe",
//"gitlens.gutterUncommittedForegroundColor": "#00bcf299",
//"gitlens.lineHighlightBackgroundColor": "#00bcf233",
//"gitlens.lineHighlightOverviewRulerColor": "#00bcf299",
//"gitlens.mergedPullRequestIconColor": "#a371f7",
//"gitlens.openAutolinkedIssueIconColor": "#3fb950",
//"gitlens.openPullRequestIconColor": "#3fb950",
//"gitlens.trailingLineBackgroundColor": "#00000000",
//"gitlens.trailingLineForegroundColor": "#99999959",
//"gitlens.unpublishedCommitIconColor": "#35b15e",
//"gitlens.unpulledChangesIconColor": "#b15e35",
//"gitlens.unpushlishedChangesIconColor": "#35b15e",
//"icon.foreground": "#c5c5c5",
//"inputOption.activeBackground": "#66666666",
//"inputOption.activeForeground": "#ffffff",
//"inputOption.hoverBackground": "#5a5d5e80",
//"interactive.activeCodeBorder": "#222222",
//"interactive.inactiveCodeBorder": "#000000",
//"keybindingLabel.background": "#8080802b",
//"keybindingLabel.border": "#33333399",
//"keybindingLabel.bottomBorder": "#44444499",
//"keybindingLabel.foreground": "#cccccc",
//"keybindingTable.headerBackground": "#ffffff0a",
//"keybindingTable.rowsBackground": "#ffffff0a",
//"list.deemphasizedForeground": "#8c8c8c",
//"list.errorForeground": "#f88070",
//"list.filterMatchBackground": "#444466aa",
//"list.focusHighlightForeground": "#ffffff",
//"list.focusOutline": "#666666",
//"list.invalidItemForeground": "#b89500",
//"list.warningForeground": "#cca700",
//"listFilterWidget.background": "#653723",
//"listFilterWidget.noMatchesOutline": "#be1100",
//"listFilterWidget.outline": "#00000000",
//"menu.selectionBackground": "#111111",
//"menu.selectionForeground": "#ffffff",
//"menu.separatorBackground": "#bbbbbb",
//"menubar.selectionBackground": "#ffffff1a",
//"menubar.selectionForeground": "#888888",
//"merge.commonContentBackground": "#60606029",
//"merge.commonHeaderBackground": "#60606066",
//"minimap.errorHighlight": "#ff1212b3",
//"minimap.findMatchHighlight": "#d18616",
//"minimap.foregroundOpacity": "#000000",
//"minimap.selectionHighlight": "#264f78",
//"minimap.selectionOccurrenceHighlight": "#676767",
//"minimap.unicodeHighlight": "#d18616",
//"minimap.warningHighlight": "#88bbff",
//"minimapGutter.addedBackground": "#587c0c",
//"minimapGutter.deletedBackground": "#94151b",
//"minimapGutter.modifiedBackground": "#0c7d9d",
//"minimapSlider.activeBackground": "#ffffff09",
//"minimapSlider.background": "#ffffff09",
//"minimapSlider.hoverBackground": "#ffffff09",
//"notebook.cellBorderColor": "#000000",
//"notebook.cellEditorBackground": "#111111",
//"notebook.cellInsertionIndicator": "#666666",
//"notebook.cellStatusBarItemHoverBackground": "#ffffff26",
//"notebook.cellToolbarSeparator": "#80808059",
//"notebook.focusedCellBorder": "#666666",
//"notebook.focusedEditorBorder": "#666666",
//"notebook.inactiveFocusedCellBorder": "#000000",
//"notebook.selectedCellBackground": "#000000",
//"notebook.selectedCellBorder": "#000000",
//"notebook.symbolHighlightBackground": "#ffffff0b",
//"notebookScrollbarSlider.activeBackground": "#ffffff12",
//"notebookScrollbarSlider.background": "#ffffff12",
//"notebookScrollbarSlider.hoverBackground": "#ffffff12",
//"notebookStatusErrorIcon.foreground": "#88bbff",
//"notebookStatusRunningIcon.foreground": "#ffffff",
//"notebookStatusSuccessIcon.foreground": "#89d185",
//"notificationCenterHeader.background": "#424242",
//"notificationLink.foreground": "#3794ff",
//"notifications.background": "#333333",
//"notifications.border": "#424242",
//"notifications.foreground": "#ffffff",
//"notificationsErrorIcon.foreground": "#ee5500",
//"notificationsInfoIcon.foreground": "#3794ff",
//"notificationsWarningIcon.foreground": "#88bbff",
//"panel.dropBorder": "#ffffff",
//"panelSection.border": "#111111",
//"panelSection.dropBackground": "#111111bb",
//"panelSectionHeader.background": "#80808033",
//"ports.iconRunningProcessForeground": "#88cc44",
//"problemsErrorIcon.foreground": "#ee5500",
//"problemsInfoIcon.foreground": "#3794ff",
//"problemsWarningIcon.foreground": "#88bbff",
//"quickInput.background": "#333333",
//"quickInput.foreground": "#ffffff",
//"quickInputList.focusBackground": "#111111",
//"quickInputList.focusForeground": "#ffffff",
//"quickInputTitle.background": "#ffffff1b",
//"sash.hoverBorder": "#666666",
//"scm.providerBorder": "#454545",
//"searchEditor.findMatchBackground": "#44446670",
//"searchEditor.textInputBorder": "#333333",
//"settings.checkboxBackground": "#222222",
//"settings.checkboxBorder": "#222222",
//"settings.checkboxForeground": "#888888",
//"settings.dropdownBackground": "#222222",
//"settings.dropdownBorder": "#222222",
//"settings.dropdownForeground": "#888888",
//"settings.dropdownListBorder": "#333333",
//"settings.focusedRowBackground": "#80808024",
//"settings.focusedRowBorder": "#ffffff1f",
//"settings.headerForeground": "#e7e7e7",
//"settings.modifiedItemIndicator": "#0c7d9d",
//"settings.numberInputBackground": "#333333",
//"settings.numberInputBorder": "#333333",
//"settings.numberInputForeground": "#ffffff",
//"settings.rowHoverBackground": "#80808012",
//"settings.textInputBackground": "#333333",
//"settings.textInputBorder": "#333333",
//"settings.textInputForeground": "#ffffff",
//"sideBar.dropBackground": "#111111bb",
//"sideBySideEditor.horizontalBorder": "#111111",
//"sideBySideEditor.verticalBorder": "#111111",
//"statusBar.debuggingBorder": "#111111",
//"statusBar.noFolderBorder": "#111111",
//"statusBarItem.compactHoverBackground": "#ffffff33",
//"statusBarItem.errorBackground": "#0066eb",
//"statusBarItem.errorForeground": "#ffffff",
//"statusBarItem.prominentForeground": "#666666",
//"statusBarItem.remoteBackground": "#88cc44",
//"statusBarItem.remoteForeground": "#222222",
//"statusBarItem.warningBackground": "#0066eb",
//"statusBarItem.warningForeground": "#ffffff",
//"symbolIcon.arrayForeground": "#ffffff",
//"symbolIcon.booleanForeground": "#ffffff",
//"symbolIcon.classForeground": "#ee9d28",
//"symbolIcon.colorForeground": "#ffffff",
//"symbolIcon.constantForeground": "#ffffff",
//"symbolIcon.constructorForeground": "#b180d7",
//"symbolIcon.enumeratorForeground": "#ee9d28",
//"symbolIcon.enumeratorMemberForeground": "#75beff",
//"symbolIcon.eventForeground": "#ee9d28",
//"symbolIcon.fieldForeground": "#75beff",
//"symbolIcon.fileForeground": "#ffffff",
//"symbolIcon.folderForeground": "#ffffff",
//"symbolIcon.functionForeground": "#b180d7",
//"symbolIcon.interfaceForeground": "#75beff",
//"symbolIcon.keyForeground": "#ffffff",
//"symbolIcon.keywordForeground": "#ffffff",
//"symbolIcon.methodForeground": "#b180d7",
//"symbolIcon.moduleForeground": "#ffffff",
//"symbolIcon.namespaceForeground": "#ffffff",
//"symbolIcon.nullForeground": "#ffffff",
//"symbolIcon.numberForeground": "#ffffff",
//"symbolIcon.objectForeground": "#ffffff",
//"symbolIcon.operatorForeground": "#ffffff",
//"symbolIcon.packageForeground": "#ffffff",
//"symbolIcon.propertyForeground": "#ffffff",
//"symbolIcon.referenceForeground": "#ffffff",
//"symbolIcon.snippetForeground": "#ffffff",
//"symbolIcon.stringForeground": "#ffffff",
//"symbolIcon.structForeground": "#ffffff",
//"symbolIcon.textForeground": "#ffffff",
//"symbolIcon.typeParameterForeground": "#ffffff",
//"symbolIcon.unitForeground": "#ffffff",
//"symbolIcon.variableForeground": "#75beff",
//"tab.activeForeground": "#ffffff",
//"tab.activeModifiedBorder": "#3399cc",
//"tab.inactiveModifiedBorder": "#3399cc80",
//"tab.lastPinnedBorder": "#585858",
//"tab.unfocusedActiveBackground": "#222222",
//"tab.unfocusedActiveModifiedBorder": "#3399cc80",
//"tab.unfocusedInactiveBackground": "#111111",
//"tab.unfocusedInactiveModifiedBorder": "#3399cc40",
//"terminal.border": "#111111",
//"terminal.dropBackground": "#111111bb",
//"terminal.selectionBackground": "#ffffff40",
//"testing.iconErrored": "#f14c4c",
//"testing.iconFailed": "#f14c4c",
//"testing.iconPassed": "#73c991",
//"testing.iconQueued": "#cca700",
//"testing.iconSkipped": "#848484",
//"testing.iconUnset": "#848484",
//"testing.message.error.decorationForeground": "#ee5500",
//"testing.message.error.lineBackground": "#ff000033",
//"testing.message.info.decorationForeground": "#ffffff80",
//"testing.peekBorder": "#ee5500",
//"testing.peekHeaderBackground": "#ee55001a",
//"testing.runAction": "#73c991",
//"textBlockQuote.background": "#7f7f7f1a",
//"textBlockQuote.border": "#007acc80",
//"textCodeBlock.background": "#0a0a0a66",
//"textLink.activeForeground": "#3794ff",
//"textLink.foreground": "#3794ff",
//"textPreformat.foreground": "#d7ba7d",
//"textSeparator.foreground": "#ffffff2e",
//"toolbar.activeBackground": "#63666750",
//"toolbar.hoverBackground": "#5a5d5e50",
//"tree.indentGuidesStroke": "#585858",
//"tree.tableColumnsBorder": "#cccccc20",
//"tree.tableOddRowsBackground": "#ffffff0a",
//"welcomePage.progress.background": "#333333",
//"welcomePage.progress.foreground": "#3794ff",
//"welcomePage.tileBackground": "#333333",
//"welcomePage.tileHoverBackground": "#3d3d3d",
//"welcomePage.tileShadow": "#111111",
//"activityBar.activeBackground": null,
//"activityBar.activeFocusBorder": null,
//"button.border": null,
//"contrastActiveBorder": null,
//"contrastBorder": null,
//"debugToolBar.border": null,
//"diffEditor.border": null,
//"dropdown.listBackground": null,
//"editor.findMatchBorder": null,
//"editor.findMatchHighlightBorder": null,
//"editor.findRangeHighlightBorder": null,
//"editor.rangeHighlightBorder": null,
//"editor.selectionForeground": null,
//"editor.selectionHighlightBorder": null,
//"editor.snippetFinalTabstopHighlightBackground": null,
//"editor.snippetTabstopHighlightBorder": null,
//"editor.symbolHighlightBorder": null,
//"editor.wordHighlightBorder": null,
//"editor.wordHighlightStrongBorder": null,
//"editorCursor.background": null,
//"editorError.background": null,
//"editorError.border": null,
//"editorGhostText.background": null,
//"editorGhostText.border": null,
//"editorGroup.emptyBackground": null,
//"editorGroup.focusedEmptyBorder": null,
//"editorGroupHeader.border": null,
//"editorHint.border": null,
//"editorInfo.background": null,
//"editorInfo.border": null,
//"editorOverviewRuler.background": null,
//"editorSuggestWidget.selectedIconForeground": null,
//"editorUnnecessaryCode.border": null,
//"editorWarning.background": null,
//"editorWidget.resizeBorder": null,
//"inputValidation.errorForeground": null,
//"inputValidation.infoForeground": null,
//"inputValidation.warningForeground": null,
//"list.activeSelectionIconForeground": null,
//"list.filterMatchBorder": null,
//"list.inactiveFocusBackground": null,
//"list.inactiveFocusOutline": null,
//"list.inactiveSelectionIconForeground": null,
//"menu.border": null,
//"menu.selectionBorder": null,
//"menubar.selectionBorder": null,
//"minimap.background": null,
//"notebook.cellHoverBackground": null,
//"notebook.focusedCellBackground": null,
//"notebook.inactiveSelectedCellBorder": null,
//"notebook.outputContainerBackgroundColor": null,
//"notebook.outputContainerBorderColor": null,
//"notificationCenter.border": null,
//"notificationCenterHeader.foreground": null,
//"notificationToast.border": null,
//"panelInput.border": null,
//"panelSectionHeader.border": null,
//"panelSectionHeader.foreground": null,
//"peekViewEditor.matchHighlightBorder": null,
//"quickInput.list.focusBackground": null,
//"quickInputList.focusIconForeground": null,
//"searchEditor.findMatchBorder": null,
//"sideBarSectionHeader.border": null,
//"tab.activeBorder": null,
//"tab.activeBorderTop": null,
//"tab.hoverBackground": null,
//"tab.hoverBorder": null,
//"tab.hoverForeground": null,
//"tab.unfocusedActiveBorderTop": null,
//"tab.unfocusedHoverBackground": null,
//"tab.unfocusedHoverBorder": null,
//"tab.unfocusedHoverForeground": null,
//"terminal.tab.activeBorder": null,
//"terminalCursor.background": null,
//"terminalCursor.foreground": null,
//"testing.message.info.lineBackground": null,
//"titleBar.border": null,
//"toolbar.hoverOutline": null,
//"welcomePage.background": null,
//"window.activeBorder": null,
//"window.inactiveBorder": null
},
"tokenColors": [
{
"scope": [
"variable.language.this"
],
"settings": {
"fontStyle": ""
}
},
{
"scope": "markup.bold",
"settings": {
"fontStyle": "bold"
}
},
{
"scope": [
"invalid",
"markup.italic",
"markup.quote"
],
"settings": {
"fontStyle": "italic"
}
},
{
"scope": "markup.underline",
"settings": {
"fontStyle": "underline"
}
},
{
"scope": [
"source.js.jsx punctuation.section.embedded",
"entity.name.tag",
"string.other.link.description.title",
"support.constant",
"support.variable",
"support.type",
"variable.other.class",
"support.class.builtin.js",
"support.class.console.js",
"meta.property-value",
"variable.parameter.keyframe-list",
"meta.at-rule.keyframes entity.name.function",
"expression.embedded.vue punctuation.definition"
],
"settings": {
"foreground": "#BBA0FF",
"fontStyle": ""
}
},
{
"scope": [
"entity.other.attribute-name.pseudo-class.css",
"entity.name.type.object.console",
"variable.language",
"variable.parameter.function.language.special.self.python",
"storage.type",
"entity.other.attribute-name.pseudo-element.css"
],
"settings": {
"foreground": "#BBA0FF",
"fontStyle": "italic"
}
},
{
"scope": [
"punctuation.definition.string.template"
],
"settings": {
"foreground": "#BBA0FF",
"fontStyle": "bold"
}
},
{
"scope": [
"entity.other.attribute-name.class.css",
"entity.other.attribute-name.parent-selector-suffix.css",
"entity.other.attribute-name.parent-selector-suffix.css punctuation.definition.entity.css",
"meta.definition.function",
"markup.underline.link",
"markup.inserted",
"meta.function-call",
"meta.instance.constructor",
"meta.attribute-with-value.class string",
"string.other.ref",
"string.other.restructuredtext.ref",
"variable.function",
"entity.name.type",
"entity.name.function",
"variable.other.object.property",
"punctuation.separator.key-value",
"meta.definition.function.js",
"support.class.component.js",
"entity.other.inherited-class",
"support.class",
"support.function.misc",
"support.function",
"entity.other.attribute-name.id.css",
"entity.other.attribute-name.id.css punctuation",
"entity.other.attribute-name.class.css punctuation",
"meta.function-call support.function.construct",
"entity.other.attribute-name"
],
"settings": {
"foreground": "#FFDD44"
}
},
{
"scope": "storage.type.function.arrow",
"settings": {
"foreground": "#FFDD44",
"fontStyle": ""
}
},
{
"scope": [
"entity.name.section",
"constant.numeric.line-number.match.find-in-files",
"markup.heading",
"markup.changed",
"meta.attribute-with-value.id string",
"string",
"punctuation.definition.string.begin",
"punctuation.definition.string.end",
"meta.attribute-selector"
],
"settings": {
"foreground": "#88CC44"
}
},
{
"scope": [
"keyword",
"keyword.control",
"constant",
"constant.numeric",
"constant.language",
"constant.other.property",
"constant.character.escape",
"comment keyword.codetag.notation",
"keyword.other.template.begin",
"keyword.other.template.end",
"markup.raw",
"markup.deleted",
"meta.property-list.css variable.other",
"entity.name.constant.preprocessor",
"meta.preprocessor",
"punctuation.section.embedded",
"punctuation.template-string.element.begin",
"punctuation.template-string.element.end",
"string.quoted.template punctuation.definition.string.begin",
"string.quoted.template punctuation.definition.string.end",
"meta.paragraph.markdown meta.dummy.line-break",
"meta.paragraph.markdown meta.hard-line-break.markdown",
"storage",
"storage.class.restructuredtext.ref",
"string.other.link.title",
"string.other.link.description",
"string.regexp punctuation.definition.string.begin",
"string.regexp punctuation.definition.string.end",
"variable.language.arguments",
"storage.modifier",
"keyword.operator.new",
"keyword.operator",
"keyword.operator.spread",
"punctuation.section.embedded.end.php source.php",
"support.function.construct",
"meta.at-rule.keyframes",
"meta.at-rule.keyframes entity.other.attribute-name"
],
"settings": {
"foreground": "#88BBFF"
}
},
{
"scope": [
"variable.other.substitution"
],
"settings": {
"foreground": "#88BBFF",
"fontStyle": "bold"
}
},
{
"scope": [
"meta.function-call meta.function-call.arguments",
"meta.function-call meta.arguments",
"meta.function-call meta.group",
"source.json meta.structure.dictionary",
"meta.object.member",
"punctuation.definition.group",
"string.unquoted.label",
"variable.other.member",
"entity.name.class",
"entity.name.namespace",
"constant.other",
"variable",
"variable.other",
"variable.other.constant.js",
"text.find-in-files",
"source",
"entity.name.type.module",
"source.sql support.function",
"support.other.namespace.php"
],
"settings": {
"foreground": "#FFFFFF",
"fontStyle": ""
}
},
{
"scope": [
"variable.parameter",
"parameters variable.function"
],
"settings": {
"foreground": "#FFFFFF",
"fontStyle": "italic"
}
},
{
"scope": [
"variable.other.property",
"support.variable.property",
"punctuation.separator.key-value",
"meta.object-literal.key",
"variable.other.object.property",
"variable.object.property",
"text.html.basic",
"text.html.vue-html",
"text.html.php",
"text.html.derivative",
"punctuation.definition.variable",
"punctuation.definition.keyword.scss",
"meta.jsx.children.js",
"meta.tag.attributes keyword.operator.assignment",
"support.type.vendored.property-name.css",
"support.type.property-name.json",
"variable.other.constant.property"
],
"settings": {
"foreground": "#BBBBCC"
}
},
{
"scope": "meta.property-name support.type",
"settings": {
"foreground": "#BBBBCC",
"fontStyle": ""
}
},
{
"scope": [
"keyword.other.substitution",
"keyword.operator.heading.restructuredtext",
"keyword.operator.table.row.restructuredtext",
"keyword.operator.table.data.restructuredtext",
"punctuation",
"markup.ignored",
"markup.untracked",
"meta.brace.round",
"meta.brace.square",
"meta.brace.curly",
"meta.delimiter.comma.js",
"meta.function-call.without-arguments.js",
"meta.function-call.method.without-arguments.js",
"source.scss",
"string source punctuation.section.embedded",
"punctuation.definition.tag.begin source",
"source.php"
],
"settings": {
"foreground": "#9999AA"
}
},
{
"scope": [
"comment",
"comment punctuation"
],
"settings": {
"foreground": "#888899",
"fontStyle": "italic"
}
},
{
"scope": "token.info-token",
"settings": {
"foreground": "#6796E6"
}
},
{
"scope": "token.warn-token",
"settings": {
"foreground": "#CD9731"
}
},
{
"scope": "token.error-token",
"settings": {
"foreground": "#F44747"
}
},
{
"scope": "token.debug-token",
"settings": {
"foreground": "#B267E6"
}
}
]
}
File renamed without changes.
File renamed without changes.
+41
View File
@@ -0,0 +1,41 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Spark Client",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}/build/Debug/bin/net6.0-windows/Spark.exe",
"cwd": "${workspaceFolder}/build/Debug/bin/net6.0-windows",
"enableStepFiltering": false,
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": "Spark Test",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}/build/Debug/bin/net6.0/sparkcmd.exe",
"args": ["test", "${input:test}"],
"cwd": "${workspaceFolder}/build/Debug/bin/net6.0-windows",
"enableStepFiltering": false,
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": "Attach (.NET Core)",
"type": "coreclr",
"request": "attach"
}
],
"inputs": [
{
"id": "test",
"description": "The test(s) to run",
"type": "promptString"
}
]
}
+37
View File
@@ -0,0 +1,37 @@
{
"cmake.configureOnOpen": false,
"workbench.colorTheme": "Default Dark+",
"C_Cpp.intelliSenseEngine": "Disabled",
"files.associations": {
"*.js": "javascript",
"*.conf": "jsonc",
"array": "cpp",
"xtree": "cpp",
"chrono": "cpp",
"*.ipp": "cpp",
"optional": "cpp",
"regex": "cpp",
"system_error": "cpp",
"format": "cpp",
"future": "cpp",
"istream": "cpp",
"memory": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"variant": "cpp",
"xlocmes": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xutility": "cpp",
"xstring": "cpp",
"string": "cpp",
"cstdint": "cpp"
},
"files.exclude": {
"**/.g.cs": true,
"**/.g.i.cs": true
}
}
+44
View File
@@ -0,0 +1,44 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build Spark Client",
"type": "process",
"command": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Common7\\Tools\\VsDevCmd.bat",
"args": [
"-arch=x64",
"-host_arch=x64",
"&&",
"${workspaceRoot}\\tools\\buildspark.cmd"
],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "new",
"showReuseMessage": false,
"clear": false,
"close": false
}
},
{
"label": "Run Spark Client",
"type": "process",
"command": "${workspaceRoot}\\build\\Debug\\bin\\net6.0-windows\\Spark.exe",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
},
"problemMatcher": []
}
]
}
+2 -2
View File
@@ -1,8 +1,8 @@
cmake_minimum_required(VERSION 3.5)
project(doc)
include(${CMAKE_SOURCE_DIR}/tools/safe_dep_glob.cmake)
include(${CMAKE_SOURCE_DIR}/tools/Protobuf.cmake)
include(${CMAKE_SOURCE_DIR}/cmake/safe_dep_glob.cmake)
include(${CMAKE_SOURCE_DIR}/cmake/Protobuf.cmake)
# DEPENDENCIES
set(DOC_GLOBS
+1 -1
View File
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "2.1.508",
"version": "6.0.200",
"rollForward": "latestMajor"
}
}
-10
View File
@@ -12,8 +12,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sparkcmd", "src\client\spar
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_core", "src\client\spark_core\spark_core.csproj", "{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", "build\ZERO_CHECK.vcxproj", "{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_sdk", "src\client\spark_sdk\spark_sdk.csproj", "{6963C314-83C4-4667-B0D0-C2F7AE208C29}"
ProjectSection(ProjectDependencies) = postProject
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40} = {9FA60215-26AF-3EB7-AB89-D4F4B126EF40}
@@ -69,14 +67,6 @@ Global
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.Build.0 = Release|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.Build.0 = Release|x64
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.Debug|x64.ActiveCfg = Debug|x64
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.Debug|x64.Build.0 = Debug|x64
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.Release|x64.ActiveCfg = Release|x64
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.Release|x64.Build.0 = Release|x64
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.ActiveCfg = Debug|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.Build.0 = Debug|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x64.ActiveCfg = Release|x64
+1
View File
@@ -12,6 +12,7 @@
<EnableDefaultContentItems>False</EnableDefaultContentItems>
<ShowMissingItemTypes>false</ShowMissingItemTypes>
<Configuration Condition="'$(configuration)'==''">Debug</Configuration>
<EnablePreviewFeatures>true</EnablePreviewFeatures>
</PropertyGroup>
<PropertyGroup Label="Output">
+10
View File
@@ -68,6 +68,16 @@
</ItemGroup>
</Target>
<Target Name="RemoveSystemRuntimeFromRefPack"
BeforeTargets="_HandlePackageFileConflicts"
Condition="'@(Reference -> WithMetadataValue('NugetPackageId', 'System.Runtime.Experimental'))' != ''">
<ItemGroup>
<Reference Remove="@(Reference)"
Condition="$([System.String]::Copy(%(Reference.Identity)).Contains('System.Runtime.dll')) and
'%(Reference.NuGetPackageId)' == 'Microsoft.NETCore.App.Ref'" />
</ItemGroup>
</Target>
<Target
Name="AfterClean"
AfterTargets="Clean">
@@ -1,4 +1,7 @@
#nullable enable
namespace mbts.spark {
using bts.api.analytics;
using mbts.analytics;
using mbts.ui;
using mbts.ui.shell;
@@ -12,9 +15,9 @@ namespace mbts.spark {
readonly AnalyticsExpirationParameters _committed_value;
readonly Property<bool> _is_selected;
readonly Property<SecurityExpiration> _driver;
readonly Property<SecurityExpiration> _deliverable;
readonly Property<SecurityExpiration> _roll_schedule;
readonly Property<ExpirationDriverImmutable?> _driver;
readonly Property<SecurityExpiration?> _deliverable;
readonly Property<SecurityExpiration?> _roll_schedule;
readonly Property<double> _roll_target;
readonly Property<double> _riskless_rate;
readonly Property<double> _settlement_price;
@@ -33,18 +36,19 @@ namespace mbts.spark {
bool _is_last_row_of_month_group;
public AnalyticsExpirationParametersRowVM(AnalyticsExpirationParametersVM owner, AnalyticsExpirationParameters committed_value) {
this.owner = owner ?? throw new ArgumentNullException(nameof(owner));
_committed_value = committed_value ?? throw new ArgumentNullException(nameof(committed_value));
public AnalyticsExpirationParametersRowVM(
AnalyticsExpirationParametersVM owner, AnalyticsExpirationParameters committed_value) {
this.owner = owner;
_committed_value = committed_value;
security = committed_value.security ?? throw new ArgumentException("security must be non-null", nameof(committed_value));
_is_selected = backing(nameof(is_selected), false);
_is_selected.Changed += (oldval, newval) => is_selected_changed?.Invoke(newval);
var is_dirty_srcs = new List<IObservable<bool>>();
(_driver, _is_driver_dirty) = mk_cell_props(nameof(driver), committed_value.driver_security);
(_deliverable, _is_deliverable_dirty) = mk_cell_props(nameof(deliverable), committed_value.deliverable_security);
(_roll_schedule, _is_roll_schedule_dirty) = mk_cell_props(nameof(roll_schedule), committed_value.roll_schedule_expiration);
(_driver, _is_driver_dirty) = mk_cell_props<ExpirationDriverImmutable?>(nameof(driver), committed_value.driver);
(_deliverable, _is_deliverable_dirty) = mk_cell_props<SecurityExpiration?>(nameof(deliverable), committed_value.deliverable_security);
(_roll_schedule, _is_roll_schedule_dirty) = mk_cell_props<SecurityExpiration?>(nameof(roll_schedule), committed_value.roll_schedule_expiration);
(_roll_target, _is_roll_target_dirty) = mk_cell_props(nameof(roll_target), committed_value.roll_target);
(_riskless_rate, _is_riskless_rate_dirty) = mk_cell_props(nameof(riskless_rate), committed_value.riskless_rate);
(_settlement_price, _is_settlement_price_dirty) = mk_cell_props(nameof(settlement_price), committed_value.settlement_price);
@@ -64,13 +68,22 @@ namespace mbts.spark {
}
}
public event Action<bool> is_selected_changed;
public event Action<bool>? is_selected_changed;
public AnalyticsExpirationParametersVM owner { get; }
public SecurityExpiration security { get; }
public SecurityExpiration driver { get => _driver.Value; set => _driver.set(value); }
public SecurityExpiration deliverable { get => _deliverable.Value; set => _deliverable.set(value); }
public SecurityExpiration roll_schedule { get => _roll_schedule.Value; set => _roll_schedule.set(value); }
public ExpirationDriverImmutable? driver {
get => _driver.Value;
set => _driver.set(value);
}
public SecurityExpiration? deliverable {
get => _deliverable.Value;
set => _deliverable.set(value);
}
public SecurityExpiration? roll_schedule {
get => _roll_schedule.Value;
set => _roll_schedule.set(value);
}
public AnalyticsExpirationParameters original_params => _committed_value;
public double roll_target { get => _roll_target.Value; set => _roll_target.set(value); }
@@ -102,15 +115,15 @@ namespace mbts.spark {
public AnalyticsExpirationParameters candidate_value => new(
security,
driver,
deliverable.is_empty() ? null : deliverable,
roll_schedule.is_empty() ? null : roll_schedule,
deliverable?.is_empty() ?? false ? null : deliverable,
roll_schedule?.is_empty() ?? false ? null : roll_schedule,
roll_target,
riskless_rate,
settlement_price,
delta_beta,
vega_beta);
public IObservable<SecurityExpiration> observe_roll_schedule() =>
public IObservable<SecurityExpiration?> observe_roll_schedule() =>
_roll_schedule.observe_current(true);
public IObservable<bool> observe_roll_schedule_dirty() =>
@@ -120,7 +133,7 @@ namespace mbts.spark {
_is_dirty.observe_current(true);
public void revert() {
driver = _committed_value.driver_security;
driver = _committed_value.driver;
deliverable = _committed_value.deliverable_security;
roll_schedule = _committed_value.roll_schedule_expiration;
roll_target = _committed_value.roll_target;
@@ -133,11 +146,11 @@ namespace mbts.spark {
public override string ToString() =>
$"sec: {security}; drv: {driver}; dlv: {deliverable}; roll: {roll_schedule} @ {roll_target}";
public bool Equals(AnalyticsExpirationParametersRowVM other) =>
public bool Equals(AnalyticsExpirationParametersRowVM? other) =>
other is not null &&
security.Equals(other.security);
public override bool Equals(object obj) =>
public override bool Equals(object? obj) =>
Equals(obj as AnalyticsExpirationParametersRowVM);
public override int GetHashCode() =>
@@ -1,5 +1,8 @@
namespace mbts.spark {
#nullable enable
namespace mbts.spark {
using bts.api;
using bts.api.analytics;
using bts.collections;
using bts.reactive;
using bts.utils;
@@ -12,11 +15,15 @@
using mbts.ui.utility;
using mbts.utils;
using Spark.Core.Collections;
using Spark.ViewModel.Commands;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
@@ -27,24 +34,32 @@
readonly IBus _bus;
readonly ObservableCollection<AnalyticsExpirationParameters> _parameters = new();
readonly DeferrableActionWrapper _sync_visible_rows;
readonly Property<AnalyticsExpirationParametersRowVM> _copy_row_source;
readonly Property<AnalyticsExpirationParametersRowVM?> _copy_row_source;
readonly Property<bool> _auto_copy_rolls_is_checked;
readonly Property<bool> _auto_copy_rates_is_checked;
readonly DelegateProperty<bool> _is_dirty;
readonly HashSet<AnalyticsExpirationParametersRowVM> _selected_rows = new();
readonly ObservableHashSet<AnalyticsExpirationParametersRowVM> _selected_rows = new();
readonly DeferrableActionWrapper _raise_selected_rows_changed;
readonly IRaiseCanExecuteChangedCommand _set_driver_to_nearest_exp_cmd;
AnalyticsExpirationParametersMap _parameter_map;
bool _auto_copy_rolls_is_checked;
bool _auto_copy_rates_is_checked;
AnalyticsExpirationParametersMap? _parameter_map;
(ICommand cmd, IDisposable can_exe_sub)? _smart_copy_roll_target_to_selection_cmd;
(ICommand cmd, IDisposable can_exe_sub)? _smart_copy_riskless_rate_to_selection_cmd;
public AnalyticsExpirationParametersVM(IBus bus, AnalyticsExpirationParametersSettings startup_data) {
_bus = bus ?? throw new ArgumentNullException(nameof(bus));
public AnalyticsExpirationParametersVM(
IBus bus, AnalyticsExpirationParametersSettings startup_data) {
_bus = bus;
_auto_copy_rates_is_checked = backing(nameof(auto_copy_rates_is_checked), false);
_auto_copy_rolls_is_checked = backing(nameof(auto_copy_rolls_is_checked), false);
_raise_selected_rows_changed = new(() => selected_rows_changed?.Invoke(_selected_rows));
var selected_symbol_ref_count = new RefCountMap<string>();
_sync_visible_rows = new(() =>
visible_rows.sync_with(rows.Where(x => selected_symbol_ref_count.ContainsKey(x.security.symbol))));
visible_rows.sync_with(
rows.Where(x => selected_symbol_ref_count.ContainsKey(x.security.symbol))));
non_options_with_empty = new ObservableAggregateCollection<SecurityExpiration>(
new() { SecurityExpiration.empty }, non_options);
_copy_row_source = backing<AnalyticsExpirationParametersRowVM>(nameof(copy_row_source));
_copy_row_source = backing<AnalyticsExpirationParametersRowVM?>(nameof(copy_row_source));
_is_dirty = backing(nameof(is_dirty), () => rows.Any(r => r.is_dirty));
if (startup_data is not null) {
@@ -55,11 +70,23 @@
auto_copy_rates_is_checked = startup_data.auto_copy_rates_is_checked;
}
var explicit_drivers = new ObservableCollection<ExpirationDriverImmutable>();
drivers = ObservableAggregateCollection.create(
new() { new ExpirationDriverImmutable(new() { TimeWeightedInterpolated = new() }) },
explicit_drivers);
_set_driver_to_nearest_exp_cmd = new Command(
() => _set_driver_to_nearest_exp(_selected_rows), () => _selected_rows.Count > 0);
commit_cmd = ObservantCommand.create(_commit, out var can_commit_observer);
revert_cmd = ObservantCommand.create(_revert, out var can_revert_observer);
selected_rows_changed += _ => _set_driver_to_nearest_exp_cmd.RaiseCanExecuteChanged();
_dispose = Disposable.Create(
_selected_rows.Subscribe((s, e) => _raise_selected_rows_changed.execute()),
ObservableAutoWrapper.connect(_parameters, rows, p => new(this, p), r => r.Dispose()),
ObservableAutoWrapper.connect(
non_options,
explicit_drivers,
sec => new ExpirationDriverImmutable(new() { Security = sec.to_api_sec_exp() })),
rows.Subscribe((s, e) => _sync_visible_rows.execute()),
_bus.subscribe(SparkTags.ExpirationParametersInputTag).OnDispatcher().Subscribe(
CompositeObserver.create(
@@ -75,7 +102,8 @@
}
});
}),
ObservableAutoWrapper.connect_item_hooks(rows, r => r.observe_is_dirty().Subscribe(_ => _is_dirty.refresh())),
ObservableAutoWrapper.connect_item_hooks(
rows, r => r.observe_is_dirty().Subscribe(_ => _is_dirty.refresh())),
_is_dirty.observe_current(true).OnDispatcher().Subscribe(can_revert_observer),
Disposable.wrap_collection(rows),
Disposable.Create(() => {
@@ -84,12 +112,15 @@
}));
}
public event Action<IReadOnlySet<AnalyticsExpirationParametersRowVM>>? selected_rows_changed;
public ObservableCollection<SecurityExpiration> non_options { get; } = new();
public IReadOnlyObservableCollection<ExpirationDriverImmutable> drivers { get; }
public ObservableCollection<SecurityExpiration> non_options_with_empty { get; } = new();
public ObservableCollection<AnalyticsExpirationParametersRowVM> rows { get; } = new();
public ObservableCollection<AnalyticsExpirationParametersRowVM> visible_rows { get; } = new();
public AnalyticsExpirationParametersRowVM copy_row_source {
public AnalyticsExpirationParametersRowVM? copy_row_source {
get => _copy_row_source.Value;
set => _copy_row_source.set(value);
}
@@ -100,18 +131,29 @@
public bool is_dirty => _is_dirty.Value;
public bool auto_copy_rolls_is_checked {
get => _auto_copy_rolls_is_checked;
set => Set(ref _auto_copy_rolls_is_checked, value);
get => _auto_copy_rolls_is_checked.Value;
set => _auto_copy_rolls_is_checked.set(value);
}
public IObservable<bool> observe_auto_copy_rolls() =>
_auto_copy_rolls_is_checked.observe_current(true);
public bool auto_copy_rates_is_checked {
get => _auto_copy_rates_is_checked;
set => Set(ref _auto_copy_rates_is_checked, value);
get => _auto_copy_rates_is_checked.Value;
set => _auto_copy_rates_is_checked.set(value);
}
public IObservable<bool> observe_auto_copy_rates() =>
_auto_copy_rates_is_checked.observe_current(true);
public ICommand toggle_auto_copy_rates_cmd =>
new Command(() => auto_copy_rates_is_checked = !auto_copy_rates_is_checked);
public ICommand toggle_auto_copy_rolls_cmd =>
new Command(() => auto_copy_rolls_is_checked = !auto_copy_rolls_is_checked);
public ICommand commit_cmd { get; }
public ICommand revert_cmd { get; }
public ICommand set_driver_to_nearest_exp_cmd => _set_driver_to_nearest_exp_cmd;
public ICommand copy_driver_to_selection_cmd => _copy_to_selection_cmd((f, t) => t.driver = f.driver);
public ICommand copy_deliverable_to_selection_cmd => _copy_to_selection_cmd((f, t) => t.deliverable = f.deliverable);
public ICommand copy_roll_schedule_to_selection_cmd => _copy_to_selection_cmd((f, t) => t.roll_schedule = f.roll_schedule);
@@ -138,7 +180,7 @@
public IEnumerable<SecurityExpiration> get_smart_copy_roll_exps(
SecurityExpiration roll_schedule_expiration) {
foreach (var (exp, exp_params) in _parameter_map?.exp_map.empty_if_null()) {
foreach (var (exp, exp_params) in (_parameter_map?.exp_map).empty_if_null()) {
if (exp_params.roll_schedule_expiration.Equals(roll_schedule_expiration)) {
yield return exp;
}
@@ -152,17 +194,30 @@
auto_copy_rolls_is_checked = auto_copy_rolls_is_checked
};
Action<AnalyticsExpirationParametersRowVM> _copy_to_selection(Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
void _set_driver_to_nearest_exp(IEnumerable<AnalyticsExpirationParametersRowVM> rows) {
foreach (var r in rows) {
if (drivers.Where(d => d.HasSecurity).TryGetMinElement(
d => (r.security.expiration - d.Security.Expiration.date_time()).Ticks.abs(),
out var nearest_exp)) {
r.driver = nearest_exp;
}
}
}
Action<AnalyticsExpirationParametersRowVM> _copy_to_selection(
Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
from_row => {
foreach (var to_row in _selected_rows) {
copy_to_row(from_row, to_row);
}
};
ICommand _copy_to_selection_cmd(Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
ICommand _copy_to_selection_cmd(
Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
Command.create(_copy_to_selection(copy_to_row));
Action<AnalyticsExpirationParametersRowVM> _smart_copy_to_selection(Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
Action<AnalyticsExpirationParametersRowVM> _smart_copy_to_selection(
Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
from_row => {
foreach (var to_row in _get_smart_copy_roll_target_rows(from_row)) {
copy_to_row(from_row, to_row);
@@ -171,21 +226,26 @@
(ICommand cmd, IDisposable can_exe_sub) _smart_copy_to_selection_cmd(
Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) {
var cmd = ObservantCommand.create(
_smart_copy_to_selection(copy_to_row), observe_can_execute, out var can_exe_observer);
var can_exe_sub = _copy_row_source.observe_current(true).OnDispatcher().Subscribe(can_exe_observer);
var copy_fn = _smart_copy_to_selection(copy_to_row);
var cmd = ObservantCommand.create<AnalyticsExpirationParametersRowVM?>(
r => copy_fn(r ?? throw new InvalidOperationException()),
observe_can_execute,
out var can_exe_observer);
var can_exe_sub = _copy_row_source.observe_current(true).OnDispatcher()
.Subscribe(can_exe_observer);
return (cmd, can_exe_sub);
static IObservable<bool> observe_can_execute(AnalyticsExpirationParametersRowVM row) =>
static IObservable<bool> observe_can_execute(AnalyticsExpirationParametersRowVM? row) =>
row is null ?
Observable.Return(false) :
row.observe_roll_schedule()
.CombineLatest(row.observe_roll_schedule_dirty(), (rs, rs_dirty) => (rs, rs_dirty))
.Select(tup => !tup.rs.is_empty() && !tup.rs_dirty)
.Select(tup => !tup.rs?.is_empty() ?? false && !tup.rs_dirty)
.OnDispatcher();
}
IEnumerable<AnalyticsExpirationParametersRowVM> _get_smart_copy_roll_target_rows(AnalyticsExpirationParametersRowVM row) {
IEnumerable<AnalyticsExpirationParametersRowVM> _get_smart_copy_roll_target_rows(
AnalyticsExpirationParametersRowVM row) {
var target_exps = get_smart_copy_roll_exps(
row.original_params.roll_schedule_expiration)
.ToHashSet();
@@ -207,11 +267,13 @@
}
}
[MemberNotNull(nameof(_parameter_map))]
void _on_parameter_map(AnalyticsExpirationParametersMap parameter_map) {
bool is_first_update = _parameter_map is null;
_parameter_map = parameter_map ?? throw new ArgumentNullException(nameof(parameter_map));
_parameter_map = parameter_map;
_parameters.sync_with(parameter_map.get_sorted_exps().Select(parameter_map.get_parameter));
non_options.sync_with(parameter_map.get_sorted_exps().Where(exp => exp.security_type != SecurityType.Option));
non_options.sync_with(
parameter_map.get_sorted_exps().Where(exp => exp.security_type != SecurityType.Option));
// Set `is_last_row_of_month_group` for each row
foreach (var exp_rows in rows.GroupBy(r => r.security.expiration.Month)) {
@@ -15,12 +15,12 @@
<cv:DoubleTextConverter
x:Key="RisklessRateConverter"
Multiplier="100" />
<shell:ExpTextConverter
x:Key="ExpirationTextConverter"
ShowSymbol="True"
MapExp="True" />
<DataTemplate x:Key="ExpirationTemplate">
<TextBlock Text="{Binding Converter={StaticResource ExpirationTextConverter}}">
<CollectionViewSource x:Key="Drivers" Source="{Binding drivers}" />
<CollectionViewSource x:Key="NonOptionsWithEmpty" Source="{Binding non_options_with_empty}" />
<DataTemplate x:Key="DriverTemplate">
<TextBlock Text="{Binding Converter={x:Static shell:AnalyticsExpirationParametersView.driver_display_text_converter}}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
@@ -30,9 +30,24 @@
<Setter
Property="FontStyle"
Value="Italic" />
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
<DataTemplate x:Key="ExpirationTemplate">
<TextBlock Text="{Binding Converter={x:Static shell:AnalyticsExpirationParametersView.expiration_text_converter}}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger
Property="Text"
Value="None">
<Setter
Property="Foreground"
Value="Gray" />
Property="FontStyle"
Value="Italic" />
</Trigger>
</Style.Triggers>
</Style>
@@ -102,6 +117,20 @@
CommandParameter="{Binding}"
/>
</ContextMenu>
<Style x:Key="TextBlockCellElement" TargetType="TextBlock">
<Setter
Property="Foreground"
Value="{Binding Foreground, RelativeSource={RelativeSource AncestorType=DataGridCell}}" />
</Style>
<Style x:Key="ComboBoxCellElement" TargetType="ComboBox" BasedOn="{StaticResource {x:Type ComboBox}}">
<Setter
Property="Foreground"
Value="{Binding Foreground, RelativeSource={RelativeSource AncestorType=DataGridCell}}" />
<Setter Property="Margin" Value="2" />
<Setter Property="IsSynchronizedWithCurrentItem" Value="False" />
</Style>
</UserControl.Resources>
<Grid>
<Grid.Resources>
@@ -126,24 +155,37 @@
Margin="5,2,2,2"
TextBlock.Foreground="Black"
HeaderContent="Symbols"
ShowSelectAll="True"
/>
ShowSelectAll="True">
<c:ComboCheckBox.HeaderContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="{u:BTSColor UI.default_text}" />
</DataTemplate>
</c:ComboCheckBox.HeaderContentTemplate>
</c:ComboCheckBox>
<WrapPanel>
<TextBlock Margin="5,5,0,0" Text="Auto copy rolls:" />
<CheckBox Margin="5,5,10,0" IsChecked="{Binding auto_copy_rolls_is_checked}" />
<TextBlock
Margin="5,5,0,0" Text="Auto copy rolls:" Style="{StaticResource TextBlock.Dark}" />
<CheckBox
Margin="5,5,10,0"
IsChecked="{Binding auto_copy_rolls_is_checked}"
Style="{StaticResource CheckBox.Dark}" />
</WrapPanel>
<WrapPanel>
<TextBlock Margin='0,5,0,0' Text="Auto copy rates:" />
<CheckBox Margin="5,5,0,0" IsChecked="{Binding auto_copy_rates_is_checked}" />
<TextBlock
Margin='0,5,0,0' Text="Auto copy rates:" Style="{StaticResource TextBlock.Dark}" />
<CheckBox
Margin="5,5,0,0"
IsChecked="{Binding auto_copy_rates_is_checked}"
Style="{StaticResource CheckBox.Dark}" />
</WrapPanel>
</StackPanel>
<c:DataGridEx
x:Name="_grid"
Grid.Row="1"
ItemsSource="{Binding visible_rows}"
AlternatingRowBackground="{u:BTSColor MarketData.driver_background}"
VerticalGridLinesBrush="Gray"
Background="Transparent"
VerticalGridLinesBrush="{u:BTSColor Grid.grid_line}"
EnableRowVirtualization="True"
EnableColumnVirtualization="True"
CanUserAddRows="False"
@@ -156,35 +198,10 @@
SelectionUnit="FullRow"
SelectedUnits="{Binding selected_rows}"
PreviewMouseRightButtonUp="_grid_PreviewMouseRightButtonUp">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Setter Property="BorderThickness" Value="1" />
<Style.Triggers>
<Trigger
Property="IsSelected"
Value="True">
<Setter
Property="Background"
Value="{u:BTSColor Grid.grid_selection_background}" />
<Setter
Property="BorderBrush"
Value="{u:BTSColor Grid.grid_selection_background}" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<c:DataGridEx.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="IsSelected" Value="{Binding is_selected, Mode=TwoWay}"/>
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<Trigger
Property="IsSelected"
Value="true">
<Setter
Property="Background"
Value="{u:BTSColor Grid.grid_selection_background}" />
</Trigger>
<DataTrigger
Binding="{Binding is_last_row_of_month_group}"
Value="True">
@@ -197,7 +214,7 @@
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</c:DataGridEx.RowStyle>
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter
@@ -209,9 +226,6 @@
<Setter
Property="HorizontalContentAlignment"
Value="Center" />
<Setter
Property="BorderThickness"
Value="0,0,1,0" />
<Setter
Property="BorderBrush"
Value="Black" />
@@ -226,7 +240,7 @@
<DataGrid.Columns>
<DataGridTextColumn
Header="Security"
Binding="{Binding security, Converter={StaticResource ExpirationTextConverter}}"
Binding="{Binding security, Converter={x:Static shell:AnalyticsExpirationParametersView.expiration_text_converter}}"
IsReadOnly="True">
<DataGridTextColumn.CellStyle>
<Style
@@ -238,9 +252,6 @@
<Setter
Property="Foreground"
Value="{u:BTSColor Name=header_text}" />
<Setter
Property="BorderThickness"
Value="0" />
<Setter
Property="VerticalContentAlignment"
Value="Center" />
@@ -287,9 +298,7 @@
<DataTrigger
Binding="{Binding is_driver_dirty}"
Value="True">
<Setter
Property="BorderBrush"
Value="Red" />
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
</DataTrigger>
</Style.Triggers>
</Style>
@@ -297,10 +306,10 @@
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
ItemsSource="{Binding DataContext.non_options, RelativeSource={RelativeSource AncestorType=c:DataGridEx}}"
ItemTemplate="{StaticResource ExpirationTemplate}"
ItemsSource="{Binding Source={StaticResource Drivers}}"
ItemTemplate="{StaticResource DriverTemplate}"
SelectedItem="{Binding driver, UpdateSourceTrigger=PropertyChanged}"
Margin="2" />
Style="{StaticResource ComboBoxCellElement}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
@@ -318,20 +327,28 @@
<DataTrigger
Binding="{Binding is_deliverable_dirty}"
Value="True">
<Setter
Property="BorderBrush"
Value="Red" />
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding is_deliverable_dirty}" Value="False" />
<Condition Binding="{Binding
deliverable,
Converter={x:Static shell:AnalyticsExpirationParametersView.expiration_is_defined_converter}}"
Value="False" />
</MultiDataTrigger.Conditions>
<Setter Property="Foreground" Value="{u:BTSColor UI.default_foreground_dark}" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
ItemsSource="{Binding DataContext.non_options_with_empty, RelativeSource={RelativeSource AncestorType=c:DataGridEx}}"
ItemsSource="{Binding Source={StaticResource NonOptionsWithEmpty}}"
ItemTemplate="{StaticResource ExpirationTemplate}"
SelectedItem="{Binding deliverable, UpdateSourceTrigger=PropertyChanged}"
Margin="2" />
Style="{StaticResource ComboBoxCellElement}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
@@ -349,20 +366,28 @@
<DataTrigger
Binding="{Binding is_roll_schedule_dirty}"
Value="True">
<Setter
Property="BorderBrush"
Value="Red" />
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding is_roll_schedule_dirty}" Value="False" />
<Condition Binding="{Binding
roll_schedule,
Converter={x:Static shell:AnalyticsExpirationParametersView.expiration_is_defined_converter}}"
Value="False" />
</MultiDataTrigger.Conditions>
<Setter Property="Foreground" Value="{u:BTSColor UI.default_foreground_dark}" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
ItemsSource="{Binding DataContext.non_options_with_empty, RelativeSource={RelativeSource AncestorType=c:DataGridEx}}"
ItemsSource="{Binding Source={StaticResource NonOptionsWithEmpty}}"
ItemTemplate="{StaticResource ExpirationTemplate}"
SelectedItem="{Binding roll_schedule, UpdateSourceTrigger=PropertyChanged}"
Margin="2" />
Style="{StaticResource ComboBoxCellElement}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
@@ -378,9 +403,7 @@
<DataTrigger
Binding="{Binding is_roll_target_dirty}"
Value="True">
<Setter
Property="BorderBrush"
Value="Red" />
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
</DataTrigger>
</Style.Triggers>
</Style>
@@ -391,14 +414,16 @@
Text="{Binding roll_target, Converter={StaticResource DoubleTextConverter}}"
VerticalAlignment="Center"
Margin="2,0,2,0"
ContextMenu="{StaticResource RollTargetContextMenu}" />
ContextMenu="{StaticResource RollTargetContextMenu}"
Style="{StaticResource TextBlockCellElement}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox
Text="{Binding roll_target, Converter={StaticResource DoubleTextConverter}}"
Margin="2" />
Text="{Binding roll_target, Converter={StaticResource DoubleTextConverter}}"
Margin="2"
Style="{StaticResource TextBox.Dark}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
@@ -414,9 +439,7 @@
<DataTrigger
Binding="{Binding is_riskless_rate_dirty}"
Value="True">
<Setter
Property="BorderBrush"
Value="Red" />
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
</DataTrigger>
</Style.Triggers>
</Style>
@@ -427,12 +450,15 @@
Text="{Binding riskless_rate, Converter={StaticResource RisklessRateConverter}}"
VerticalAlignment="Center"
Margin="2,0,2,0"
ContextMenu="{StaticResource RisklessRateContextMenu}" />
ContextMenu="{StaticResource RisklessRateContextMenu}"
Style="{StaticResource TextBlockCellElement}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding riskless_rate, Converter={StaticResource RisklessRateConverter}}" />
<TextBox
Text="{Binding riskless_rate, Converter={StaticResource RisklessRateConverter}}"
Style="{StaticResource TextBox.Dark}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
@@ -448,9 +474,7 @@
<DataTrigger
Binding="{Binding is_settlement_price_dirty}"
Value="True">
<Setter
Property="BorderBrush"
Value="Red" />
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
</DataTrigger>
</Style.Triggers>
</Style>
@@ -461,12 +485,15 @@
Text="{Binding settlement_price, Converter={StaticResource DoubleTextConverter}}"
VerticalAlignment="Center"
Margin="2,0,2,0"
ContextMenu="{StaticResource SettlementPriceContextMenu}" />
ContextMenu="{StaticResource SettlementPriceContextMenu}"
Style="{StaticResource TextBlockCellElement}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding settlement_price, Converter={StaticResource DoubleTextConverter}}" />
<TextBox
Text="{Binding settlement_price, Converter={StaticResource DoubleTextConverter}}"
Style="{StaticResource TextBox.Dark}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
@@ -483,9 +510,7 @@
<DataTrigger
Binding="{Binding is_delta_beta_dirty}"
Value="True">
<Setter
Property="BorderBrush"
Value="Red" />
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
</DataTrigger>
</Style.Triggers>
</Style>
@@ -496,12 +521,15 @@
Text="{Binding delta_beta, Converter={StaticResource DoubleTextConverter}}"
VerticalAlignment="Center"
Margin="2,0,2,0"
ContextMenu="{StaticResource DeltaBetaContextMenu}" />
ContextMenu="{StaticResource DeltaBetaContextMenu}"
Style="{StaticResource TextBlockCellElement}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding delta_beta, Converter={StaticResource DoubleTextConverter}}" />
<TextBox
Text="{Binding delta_beta, Converter={StaticResource DoubleTextConverter}}"
Style="{StaticResource TextBox.Dark}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
@@ -518,9 +546,7 @@
<DataTrigger
Binding="{Binding is_vega_beta_dirty}"
Value="True">
<Setter
Property="BorderBrush"
Value="Red" />
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
</DataTrigger>
</Style.Triggers>
</Style>
@@ -528,15 +554,18 @@
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock
Text="{Binding vega_beta, Converter={StaticResource DoubleTextConverter}}"
VerticalAlignment="Center"
Margin="2,0,2,0"
ContextMenu="{StaticResource VegaBetaContextMenu}" />
Text="{Binding vega_beta, Converter={StaticResource DoubleTextConverter}}"
VerticalAlignment="Center"
Margin="2,0,2,0"
ContextMenu="{StaticResource VegaBetaContextMenu}"
Style="{StaticResource TextBlockCellElement}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding vega_beta, Converter={StaticResource DoubleTextConverter}}" />
<TextBox
Text="{Binding vega_beta, Converter={StaticResource DoubleTextConverter}}"
Style="{StaticResource TextBox.Dark}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
@@ -1,8 +1,10 @@
namespace mbts.ui.shell {
using bts.api;
#nullable enable
namespace mbts.ui.shell {
using bts.api.analytics;
using mbts.spark;
using mbts.ui.controls;
using mbts.ui.converters;
using mbts.ui.extensions;
using System;
@@ -16,8 +18,8 @@
/// Interaction logic for AnalyticsExpirationParametersView.xaml
/// </summary>
partial class AnalyticsExpirationParametersView : UserControl {
IDisposable _context_menu_op;
IDisposable _data_context_hooks;
IDisposable? _context_menu_op;
IDisposable? _data_context_hooks;
public AnalyticsExpirationParametersView() {
InitializeComponent();
@@ -31,6 +33,28 @@
}
}
public static ExpirationTextConverter expiration_text_converter =>
new() {
ShowSymbol = true,
ShowType = true,
MapExp = true
};
public static IValueConverter driver_display_text_converter =>
ValueConverter.create<ExpirationDriverImmutable?, string?>(
d => d.HasValue ?
d.Value.ModeCase switch {
ExpirationDriver.ModeOneofCase.Security =>
expiration_text_converter.convert(d.Value.Security.to_sec_exp()),
ExpirationDriver.ModeOneofCase.TimeWeightedInterpolated => "Calculate",
_ => null
} :
null);
public static IValueConverter expiration_is_defined_converter =>
ValueConverter.create<SecurityExpiration?, bool>(exp =>
exp is not null && exp.expiration != default);
void _grid_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e) {
Disposable.dispose(ref _context_menu_op);
if (e.OriginalSource is not FrameworkElement el || DataContext is not AnalyticsExpirationParametersVM vm) {
@@ -47,30 +71,4 @@
e.Handled = true;
}
}
class ExpTextConverter : IValueConverter {
public ExpTextConverter() {
NullOrEmptyText = "None";
}
public bool ShowType { get; set; }
public bool ShowSymbol { get; set; }
public bool MapExp { get; set; }
public string NullOrEmptyText { get; set; }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
var exp = value as SecurityExpiration;
if (exp == null || exp.is_empty()) {
return NullOrEmptyText;
}
return ShowSymbol ?
SecurityFormatter.format_future(exp.symbol, exp.expiration) :
DateFormatter.Format(exp.expiration, DateFormat.MonthCodeLastDigitYear);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
}
}
@@ -1,10 +1,11 @@
namespace mbts.spark {
namespace mbts.spark {
using bts.api;
using bts.spark;
using mbts.ui;
using mbts.ui.shell;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
@@ -38,11 +39,30 @@
public void thread_init() {
_vm = new AnalyticsExpirationParametersVM(_bus, _init_settings);
_view = new AnalyticsExpirationParametersView { DataContext = _vm };
var auto_copy_rolls_cmd = new SparkCommandCommand(
"Auto Copy Rolls", null, _vm.toggle_auto_copy_rolls_cmd);
_vm.SubscribeDisposed(_vm.observe_auto_copy_rolls().Subscribe(v =>
auto_copy_rolls_cmd.icon = v ? Icons.RecurringSchedule : Icons.RecurringScheduleGray));
var auto_copy_rates_cmd = new SparkCommandCommand(
"Auto Copy Rates", null, _vm.toggle_auto_copy_rates_cmd);
_vm.SubscribeDisposed(_vm.observe_auto_copy_rates().Subscribe(v =>
auto_copy_rates_cmd.icon = v ? Icons.FinancialGrowth : Icons.FinancialGrowthGray));
_commands = new() {
new SparkCommandCommand("Commit", Icons.Disk, _vm.commit_cmd, new KeyGesture(Key.S, ModifierKeys.Control)),
new SparkCommandCommand("Revert", Icons.UndoCircular, _vm.revert_cmd, new KeyGesture(Key.Z, ModifierKeys.Control)),
auto_copy_rates_cmd,
auto_copy_rolls_cmd,
new SparkCommandCommand(
"Set Driver to Nearest Exp", null, _vm.set_driver_to_nearest_exp_cmd) {
show_in_toolbar = false,
show_in_context_menu = true
},
};
_view = new AnalyticsExpirationParametersView { DataContext = _vm };
}
}
}
@@ -1,101 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using bts;
using mbts.analytics;
using bts.api.analytics;
using System.Reactive.Linq;
using bts.api;
using System.Threading;
#nullable enable
namespace mbts.spark {
// 1. Reads exp params from the network and publishes
// it to the BB
// 2. Listens to ExpirationParametersCommitTag and
// writes the calls into persistence to save the data
public class AnalyticsParametersManager : IDisposable {
private readonly ThreadedBlackboard _bb;
private AnalyticsService _analytics_service;
private List<IDisposable> _disposables = new List<IDisposable>();
private IDictionary<mbts.SecurityExpiration, AnalyticsExpirationParameters>
_data = new Dictionary<mbts.SecurityExpiration, AnalyticsExpirationParameters>();
private readonly ITag<IEnumerable<AnalyticsExpirationParameters>>
_in_bb_exp_params_commit_tag = SparkTags.ExpirationParametersCommitTag;
private readonly ITag<SystemContractData> _in_contracts_tag = SparkTags.SystemContractsTag;
private readonly ITag<AnalyticsExpirationParametersMap> _out_exp_params_tag =
SparkTags.ExpirationParametersInputTag;
private HighPerformanceTimer _timer = new HighPerformanceTimer();
using bts;
using bts.api;
using bts.api.analytics;
public AnalyticsParametersManager(ThreadedBlackboard bb,
AnalyticsService analytics_server) {
_bb = bb;
_analytics_service = analytics_server;
var exp_params_sub = _analytics_service.subscribei_exp_parameters()
.ObserveOn(SynchronizationContext.Current)
.Subscribe(_on_exp_parameters);
_disposables.Add(exp_params_sub);
_bb.subscribe(_in_bb_exp_params_commit_tag);
_bb.subscribe(_in_contracts_tag);
_bb.data_callback += _on_bb_data;
}
using mbts.analytics;
private void _on_bb_data(object tag, object data) {
if (_in_contracts_tag.Equals(tag)) {
_assemble_and_publish();
} else if (_in_bb_exp_params_commit_tag == tag) {
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
/// <summary>
/// Reads exp params from the network and publishes it to the bus; listens to
/// <see cref="SparkTags.ExpirationParametersCommitTag"/> and persists the data
/// </summary>
public sealed class AnalyticsParametersManager : IDisposable {
IDisposable? _dispose;
public AnalyticsParametersManager(IBus bus, AnalyticsService analytics_service) {
var contracts_src = bus.subscribe(SparkTags.SystemContractsTag);
var exp_params_in_src = analytics_service.subscribei_exp_parameters()
.Select(upd => upd.all
.SelectMany(ep => ep.ParamList
.Select(ep => new AnalyticsExpirationParameters(ep)))
.ToDictionary(ep => ep.security));
var exp_params_out_src = bus.subscribe(SparkTags.ExpirationParametersCommitTag)
.Select(eps => eps
.Where(ep => ep.security.expiration.Date >= DateTime.Today - TimeSpan.FromDays(1)));
_dispose = Disposable.Create(
exp_params_in_src.CombineLatest(contracts_src)
.Select(tup => new AnalyticsExpirationParametersMap(tup.First, tup.Second))
.ObserveOn(SynchronizationContext.Current ?? throw new InvalidOperationException())
.Subscribe(bus.post_callback(SparkTags.ExpirationParametersInputTag)),
exp_params_out_src.Subscribe(save_exp_params));
void save_exp_params(IEnumerable<AnalyticsExpirationParameters> exp_params) {
// listens to the commit tag and saves it
IEnumerable<AnalyticsExpirationParameters> exp_params =
data as IEnumerable<AnalyticsExpirationParameters>;
exp_params = exp_params.Where(e => e.security.expiration.Date >=
DateTime.Now.Date.Subtract(TimeSpan.FromDays(1)));
bts.Log.Gen.info(
String.Format("AnalyticsParametersManager._on_bb_data received commit count:{0}",
exp_params.Count()));
ExpirationParameterEntryList to_save = new ExpirationParameterEntryList();
Log.Gen.info($"AnalyticsParametersManager received commit req. count:{exp_params.Count()}");
var to_save = new ExpirationParameterEntryList();
to_save.ParamList.AddRange(exp_params.Select(i => i.to_exp_param_entry()));
_timer.start();
_analytics_service.set_exp_parameters(to_save);
_timer.stop();
bts.Log.Gen.info(
String.Format("AnalyticsParametersManager saved exp_params count:{0} t:{1} msecs",
exp_params.Count(), _timer.lastIntervalTime));
Log.Gen.record(
null,
(dt, elapsed, res) => {
var msg = "AnalyticsParametersManager saved exp_params. " +
$"count:{exp_params.Count()} t:{elapsed.TotalMilliseconds:0.000}ms";
return (LogLevel.Info, msg);
},
() => analytics_service.set_exp_parameters(to_save));
}
}
void _on_exp_parameters(bts.api.core.Update<ExpirationParameterEntryListImmutable, int> update) {
_data = new Dictionary<mbts.SecurityExpiration, AnalyticsExpirationParameters>();
bts.Log.Gen.info(String.Format("AnalyticsParametersManager._on_exp_parameters received count:{0}",
update.all.Count()));
bts.Log.assert(update.all.Count() == 0 || update.all.Count() == 1);
foreach (ExpirationParameterEntryListImmutable l in update.all) {
foreach (ExpirationParameterEntryImmutable e in l.ParamList) {
AnalyticsExpirationParameters new_entry = new AnalyticsExpirationParameters(e);
_data[new_entry.security] = new_entry;
}
break;
}
Log.Gen.info($"AnalyticsParametersManager._on_exp_parameters count: {_data.Count}");
_assemble_and_publish();
// _bb.post(_out_exp_params_tag, new AnalyticsExpirationParametersMap(_data));
}
private void _assemble_and_publish() {
if (_data != null) {
SystemContractData sc_data = _bb.read_state(_in_contracts_tag);
if (sc_data != null) {
_bb.post(_out_exp_params_tag, new AnalyticsExpirationParametersMap(_data, sc_data));
}
}
}
#region IDisposable
public void Dispose() {
_bb.data_callback -= _on_bb_data;
foreach (IDisposable d in _disposables) {
d.Dispose();
}
}
#endregion
public void Dispose() =>
Disposable.dispose(ref _dispose);
}
}
@@ -125,8 +125,8 @@ namespace mbts.spark {
if (_is_different(res)) {
_last_published = new OptionDriverPriceMap(_sec_tup.security_name, res);
var to_fire = new OptionDriverPriceMap(_sec_tup.security_name, res);
bts.Log.Gen.info("SingleOptionDriverPricePublisher._compute_and_fire \n" +
$"map:{to_fire.log_string()}");
// bts.Log.Gen.info("SingleOptionDriverPricePublisher._compute_and_fire \n" +
// $"map:{to_fire.log_string()}");
_logger.stop_default_timer();
_bb.post(SparkTags.OptionDriverBBOTag(_sec_tup.security_name),
new OptionDriverPriceMap(_sec_tup.security_name, res));
@@ -1,17 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using mbts.analytics;
using bts;
using bts.api.analytics;
using System.Reactive.Linq;
using System.Threading;
using bts.api;
using System.Collections;
namespace mbts.spark {
using bts;
using bts.api;
using bts.api.analytics;
using mbts.analytics;
using Spark.Core.Protobuf;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
namespace mbts.spark {
// For a single VolSurface this class
// 1. Listents to commmits and calls the service to persist data
// 2. Gathers the vol surface input from the nw and publishes it
@@ -78,11 +80,8 @@ namespace mbts.spark {
_snp_shot_map.Values);
}
static VolSurfaceInput _to_vs_input(VolSurfaceEntryImmutable vs) {
byte[] vs_bytes = vs.Volsurface.ToByteArray();
return
mbts.analytics.VolSurfaceUtilityFunctions.deserialize_proto<VolSurfaceInput>(vs_bytes);
}
static VolSurfaceInput _to_vs_input(VolSurfaceEntryImmutable vs) =>
ProtobufSerializationHelper.deserialize<VolSurfaceInput>(vs.Volsurface.ToByteArray());
private void _on_bb_data(object tag, object data) {
if (_in_bb_committ_tag.Equals(tag)) {
@@ -15,6 +15,7 @@ using System.Reactive.Linq;
using System.Collections;
using mbts.spark;
using System.DirectoryServices.ActiveDirectory;
using Spark.Core.Protobuf;
// using mbts.bb;
namespace mbts.spark {
@@ -53,6 +54,7 @@ namespace mbts.spark {
// 2. Listens to the activation tag (also published by the UI) and
// creates the SingleVolSurfaceManager for the VS
public class VolSurfaceBusManager : IDisposable {
private List<IDisposable> _disps = new List<IDisposable>();
private ThreadedBlackboard _bb;
private bts.api.analytics.AnalyticsService _analytics_service;
// in tags
@@ -77,7 +79,7 @@ namespace mbts.spark {
bts.api.analytics.AnalyticsService analytics_service) {
bts.Log.Ui.info("VSBusManager cons tid:{VolSurfaceTroubleshootingFunctions.tid()}");
_bus = bus;
_bb = new ThreadedBlackboard(bus);
_bb = new ThreadedBlackboard("AW2", bus);
_analytics_service = analytics_service;
// subs to bb
_bb.subscribe(_in_scdata_tag);
@@ -96,7 +98,7 @@ namespace mbts.spark {
.Subscribe(_on_vs_usage_update);
_subs.Add(vs_sub);
_subs.Add(vs_usage_sub);
_subs.Add(new AnalyticsParametersManager(_bb, _analytics_service));
_subs.Add(new AnalyticsParametersManager(bus, _analytics_service));
_subs.Add(new ResourceAllocator(bus, _bb));
_subs.Add(new SymbolAggregationPublisher<OptionDriverPriceMap>(
_bb, (sym) => SparkTags.OptionDriverBBOTag(sym),
@@ -106,38 +108,47 @@ namespace mbts.spark {
SparkTags.AllInterpGreeks));
_subs.Add(new LiveTheoPublisher(_bb));
_subs.Add(new VolSurfaceInterpGreeksMultiplexer(_bb));
//_subs.Add(new AnalyticsServiceTester(_bb));
// TODO: temporatily publish values
VolSurfaceUsageList ulist = new VolSurfaceUsageList();
ulist.UsageList.Add(new VolSurfaceUsageEntry() {
VsId = 6,
SecTup = new bts.api.SecurityTuple() {
Type = SecurityType.Option,
Venue = VolSurfaceTemp.get_default_venue(SecurityType.Option, "BTC"),
Symbol = "BTC"
// usage
var list_sub = _bus.subscribe(SparkTags.VolSurfaceListTag).OnDispatcher().Subscribe(t => {
VolSurfaceUsageList ulist = new VolSurfaceUsageList();
IDictionary<string, int> name_to_ids = new Dictionary<string, int>();
foreach (var kv in t) {
name_to_ids[kv.Value] = kv.Key;
}
});
ulist.UsageList.Add(new VolSurfaceUsageEntry() {
VsId = 7,
SecTup = new bts.api.SecurityTuple() {
Type = SecurityType.Option,
Venue = VolSurfaceTemp.get_default_venue(SecurityType.Option, "ETH"),
Symbol = "ETH"
Log.Ui.info($"VolSurfaceUsageList name_to_ids count: {name_to_ids.Count}");
var vs_usage = mbts.config.Configuration.get<bts.config.toggles.VolSurfaceUsage>();
Log.Ui.info($"VolSurfaceUsageList vs_usage acount: {vs_usage.vol_surface_usage.Count}");
foreach (var u in vs_usage.vol_surface_usage) {
string option_name = u.option_name;
string vs_name = u.vs_name;
int vs_key;
if (name_to_ids.TryGetValue(vs_name, out vs_key)) {
ulist.UsageList.Add(new VolSurfaceUsageEntry() {
VsId = vs_key,
SecTup = new bts.api.SecurityTuple {
Type = SecurityType.Option,
Venue = Venue.Deribit,
Symbol = option_name
}
});
} else {
Log.Gen.error($"Could not find vol surface with name: {vs_name}");
}
}
var list_imm = new VolSurfaceUsageListImmutable(ulist);
Log.Ui.info(list_imm.log_string());
_bb.post(SparkTags.VolSurfaceUsageTag, list_imm);
});
_bb.post(SparkTags.VolSurfaceUsageTag, new VolSurfaceUsageListImmutable(ulist));
_disps.Add(list_sub);
}
public ThreadedBlackboard bb() {
return _bb;
}
void _on_vs_usage_update(Update<VolSurfaceUsageListImmutable, int> update) {
// TODO
return;
// int vs_count = update.all.Count();
// Log.Gen.info($"VSBusManager._on_vs_usage_update " +
// $"tid:{Thread.CurrentThread.ManagedThreadId} count:{update.all.Count()}");
// Log.assert(vs_count <= 1);
// if (update.all.TryGetSingle(out var to_write)) {
// _bb.post(SparkTags.VolSurfaceUsageTag, to_write);
// }
}
void _on_vss(bts.api.core.Update<VolSurfaceEntryImmutable, UInt64> update) {
@@ -172,7 +183,7 @@ namespace mbts.spark {
// callback
mbts.analytics.VolSurfaceSettings vs_settings = data as mbts.analytics.VolSurfaceSettings;
bts.Log.Gen.info(String.Format("VSBusManager._on_bb_update received vs creation tag vs:{0}",
VolSurfaceUtilityFunctions.serialize_proto_to_text(vs_settings)));
ProtobufSerializationHelper.serialize_to_string(vs_settings)));
_waiting_creations.Enqueue(vs_settings);
} else if (_in_bb_delete_tag.Equals(tag)) {
int vs_id = (int)data;
+38 -6
View File
@@ -3,6 +3,8 @@ using System.Collections.Generic;
using mbts.analytics;
using bts.api;
using mbts.ui;
using MathNet.Numerics.Providers.FourierTransform;
using BCG;
namespace mbts.spark {
// Publishes theos for all options (on the side, also publishes the theos for TC2)
@@ -15,12 +17,15 @@ namespace mbts.spark {
private readonly HighPerformanceTimer _timer = new HighPerformanceTimer();
private readonly PerfStatsLogger _logger = new PerfStatsLogger(50, 100);
private readonly string _log_id = "LiveTheoPublisher";
private DateTime _last_future_theos_published = DateTime.MinValue;
private TimeSpan _futures_theos_publish_period = TimeSpan.FromMilliseconds(300);
public LiveTheoPublisher(ThreadedBlackboard bb) {
_bb = bb;
_bb.subscribe(_greeks_tag);
_bb.subscribe(_drivers_tag);
_bb.data_callback += _on_data;
_bb.timer_callback += _on_timer;
_interp_and_publish();
}
@@ -31,6 +36,10 @@ namespace mbts.spark {
}
}
private void _on_timer() {
_publish_future_theos();
}
private void _log_interpgreeks(
IReadOnlyDictionary<string, OptionTheoInterpolationData> interp_greeks) {
string log_msg = String.Empty;
@@ -127,18 +136,18 @@ namespace mbts.spark {
var k_theos = new Dictionary<SecurityStrike, TheoPoint>();
foreach (var kv in sc_data.strike_map) {
foreach (SecurityStrike k in kv.Value) {
var cp_id = k.call_put_id;
var (call_id, put_id) = k.call_put_id;
var driver = _get_option_driver(driver_map, k);
var tp = _interp_theo(interp_greeks, k, driver.get_driver());
k_theos[k] = tp;
// put it in the output map
if (cp_id.Item1.HasValue) {
res.Add(cp_id.Item1.Value,
if (call_id.HasValue) {
res.Add(call_id.Value,
new GreeksTuple(tp.vol, tp.driver, tp.call, tp.cdelta, tp.cgamma,
tp.cvega, tp.c_theta, Double.NaN));
}
if (cp_id.Item2.HasValue) {
res.Add(cp_id.Item2.Value,
if (put_id.HasValue) {
res.Add(put_id.Value,
new GreeksTuple(tp.vol, tp.driver, tp.put, tp.pdelta, tp.pgamma,
tp.pvega, tp.p_theta, Double.NaN));
}
@@ -153,8 +162,31 @@ namespace mbts.spark {
_publish_tc2_theos(k_theos);
}
// recomputes and publishes them periodicially
void _publish_future_theos() {
if (DateTime.Now - _last_future_theos_published < _futures_theos_publish_period)
return;
_last_future_theos_published = DateTime.Now;
var rv = new Dictionary<SecurityExpiration, FutureTheoStructure>();
SystemContractData sc_data = _bb.read_state(SparkTags.SystemContractsTag);
if (sc_data == null)
return;
foreach (var kv in sc_data.exp_map) {
var id = kv.Value;
SecurityMD sec_md;
if (sc_data.sec_md_map.TryGetValue(id, out sec_md)) {
if (sec_md.security.HasFuture) {
SecurityExpiration exp = kv.Key;
double pr = sec_md.md.fixing_price;
rv.Add(exp, new FutureTheoStructure(exp.expiration, pr, pr, 1, 0));
}
}
}
_bb.post(SparkTags.TC2Tags.LiveFutureTheosTag, rv);
}
public void Dispose() {
_bb.data_callback -= _on_data;
}
}
}
}
@@ -24,7 +24,7 @@ namespace mbts.spark {
var exp = kv.Key;
if (!temp.ContainsKey(kv.Key)) {
temp.Add(kv.Key,
new AnalyticsExpirationParameters(exp, empty, empty, empty, 0, 0, 0, 0, 0));
new AnalyticsExpirationParameters(exp, null, empty, empty, 0, 0, 0, 0, 0));
}
}
exp_map = temp;
@@ -1,58 +1,43 @@
using System;
using System.Collections.Generic;
using mbts.analytics;
using bts.api;
using bts.api.persistence;
using System.Linq;
#nullable enable
namespace mbts.spark {
using mbts.analytics;
using System;
using System.Collections.Generic;
using System.Linq;
// All driver prices (along with some more info) for an option symbol
public class OptionDriverPriceMap {
public readonly String option_symbol = null;
public readonly IDictionary<SecurityExpiration, DriverMD> exp_price_map = null;
public readonly string option_symbol;
public readonly IDictionary<SecurityExpiration, DriverMD> exp_price_map;
Dictionary<SecurityExpiration, DriverMD>? _unexpired_exp_price_map_backing;
public OptionDriverPriceMap(
string option_symbol_a,
IDictionary<SecurityExpiration, DriverMD> exp_price_map_a) {
option_symbol = option_symbol_a;
exp_price_map = exp_price_map_a;
}
public IDictionary<SecurityExpiration, DriverMD> unexpired_exp_price_map {
get {
return exp_price_map.Where(
kv => kv.Key.expiration >= DateTime.Now.Date).ToDictionary(
kv => kv.Key, kv => kv.Value);
}
string option_symbol, IDictionary<SecurityExpiration, DriverMD> exp_price_map) {
this.option_symbol = option_symbol;
this.exp_price_map = exp_price_map;
}
public IDictionary<SecurityExpiration, DriverMD> unexpired_exp_price_map =>
_unexpired_exp_price_map_backing ??=
exp_price_map.Where(kv => kv.Key.expiration >= DateTime.Now.Date).ToDictionary();
// this is the BS needed because of ignoring exchange
public DriverMD get_driver_md(DateTime exp) {
foreach (var kv in exp_price_map) {
if (kv.Key.expiration == exp) {
return kv.Value;
}
}
return DriverMD.empty;
}
public DriverMD get_driver_md(SecurityExpiration exp) {
if (exp_price_map.TryGetValue(exp, out var d))
return d;
return DriverMD.empty;
}
public DriverMD get_driver_md(DateTime exp) =>
exp_price_map.FirstOrDefault(kv => kv.Key.expiration == exp).Value ?? DriverMD.empty;
public DriverMD get_driver_md(SecurityExpiration exp) =>
exp_price_map.GetValueOrDefault(exp) ?? DriverMD.empty;
public static IDictionary<VolSurfaceExpiration, DriverMD> get_vs_price_map(
IReadOnlyDictionary<string, OptionDriverPriceMap> all_sym_map,
Func<string, bool> sym_filter = null) {
var rv = new Dictionary<VolSurfaceExpiration, DriverMD>();
if (all_sym_map != null)
foreach (var kv in all_sym_map) {
string sym = kv.Key;
OptionDriverPriceMap sym_map = kv.Value;
if (sym_filter == null || sym_filter(sym)) {
foreach (var kv_int in sym_map.exp_price_map) {
rv[new VolSurfaceExpiration(kv_int.Key)] = kv_int.Value;
}
}
}
return rv;
Func<string, bool>? sym_filter = null
) {
sym_filter ??= _ => true;
return all_sym_map.SafeWhere(kv => kv.Value is not null && sym_filter(kv.Key))
.SelectMany(kv => kv.Value.exp_price_map)
.ToDictionaryCrushed(kv => kv.Key.to_vs_exp(), kv => kv.Value);
}
}
}
}
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -173,7 +173,7 @@ namespace mbts.spark {
}
IDictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>> rv_data =
new Dictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>>();
return Tuple.Create(exp.to_security_expiration(), rv_data);
return Tuple.Create(exp.to_security_expiration(type: SecurityType.Option), rv_data);
}
internal IDictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>> get_option_bbo(
@@ -182,12 +182,11 @@ namespace mbts.spark {
Dictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>> rv =
new Dictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>>();
foreach (SecurityStrike k in strikes) {
var (call_id, put_id) = k.call_put_id;
// call
uint? call_id = k.call_put_id.Item1;
var call_sec_md = get_sec_md(call_id);
VolSurfaceMDUnit call_bbo = call_sec_md == null ? VolSurfaceMDUnit.empty : call_sec_md.Item2;
// put
uint? put_id = k.call_put_id.Item2;
var put_sec_md = get_sec_md(put_id);
VolSurfaceMDUnit put_bbo = put_sec_md == null ? VolSurfaceMDUnit.empty : put_sec_md.Item2;
rv.Add(k.strike, new Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>(call_bbo, put_bbo));
@@ -22,6 +22,7 @@ namespace mbts.spark {
/// from the same secondary thread.
/// </summary>
public class ThreadedBlackboard {
private readonly string _bb_name;
private IBus _bus;
private List<IDisposable> _subs = new List<IDisposable>();
private HashSet<object> _tag_map = new HashSet<object>();
@@ -31,9 +32,10 @@ namespace mbts.spark {
private IDictionary<object, object> _cache = new
Dictionary<object, object>();
private static int _tid() { return VolSurfaceTroubleshootingFunctions.tid(); }
public ThreadedBlackboard(IBus bus) {
bts.Log.Ui.info($"ThreadedBlackBoard.cons tid:{ _tid()}");
public ThreadedBlackboard(string name, IBus bus) {
bts.Log.Ui.info($"ThreadedBlackBoard.cons tid:{_tid()} bb_name: {name}");
_bus = bus;
_bb_name = name;
subscribe(SparkTags.SparkTimer);
System.Threading.Thread timer_thread = new System.Threading.Thread(() => {
DateTime start_time = DateTime.Now;
@@ -61,15 +63,13 @@ namespace mbts.spark {
return;
}
_tag_map.Add(tag);
bts.Log.Ui.info($"ThreadedBlackBoard.subscribe tag:{tag} tid:{ _tid()}");
bts.Log.Ui.info($"ThreadedBlackBoard.subscribe tag:{tag} tid:{_tid()}");
var observable = _bus.subscribe(tag).OnDispatcher().Subscribe(
data => _on_bus_data(tag, data));
_subs.Add(observable);
}
public void post<T>(ITag<T> tag, T data, bool block_until_written = false) {
bts.Log.Ui.diag($"ThreadedBlackBoard.post tag:{tag} data:{_data_string(data)} " +
$"tid:{_tid()}");
_cache[tag] = data;
_bus.post(tag, data);
}
@@ -92,8 +92,6 @@ namespace mbts.spark {
timer_callback();
return;
}
bts.Log.Ui.diag($"ThreadedBlackBoard._on_bus_data tag:{tag} data:{_data_string(data)} " +
$"tid:{_tid()}");
data_callback(tag, data);
}
@@ -1,17 +1,25 @@
using bts.api;
using bts.api.analytics;
using bts.collections;
using bts.utils;
using IronPython.Compiler.Ast;
using mbts;
using mbts.analytics;
using mbts.spark;
using mbts.ui.controls;
using mbts.ui.converters;
using mbts.ui.shell;
using Spark.Core;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using mbts;
using mbts.analytics;
using mbts.ui.controls;
using mbts.ui.shell;
using mbts.spark;
using bts.utils;
using bts.api;
using bts.collections;
using System.Collections.Immutable;
namespace mbts.spark {
/// This contains the list of global values for the vol
@@ -132,7 +140,7 @@ namespace mbts.spark {
internal static string log_string(this Theos t) {
string rv = $"strike: {t.strike} fwd: {t.fwd} driver: {t.driver} " +
$"move: { t.move} vol: {t.vol} c_theo: {t.call} " +
$"move: {t.move} vol: {t.vol} c_theo: {t.call} " +
$"p_theo: {t.put}";
return rv;
}
@@ -151,8 +159,8 @@ namespace mbts.spark {
foreach (var kv in sc_data.strike_map) {
var exp = kv.Key;
foreach (var k in kv.Value) {
rv += $"exp: {exp} k: {k} c_id: {k_id(k.call_put_id.Item1)} " +
$"p_id: {k.call_put_id.Item2}" + "\n";
rv += $"exp: {exp} k: {k} c_id: {k_id(k.call_put_id.call)} " +
$"p_id: {k.call_put_id.put}" + "\n";
}
}
return rv;
@@ -178,6 +186,58 @@ namespace mbts.spark {
return rv;
}
internal static string log_string(this ComboFullData cf_data) {
string rv = String.Empty;
if (cf_data.option_expirations != null) {
foreach (var kv in cf_data.option_pos_map) {
var exp = kv.Key;
foreach (var kv_in in kv.Value) {
double k = kv_in.Key;
ComboStrikeData kp = kv_in.Value;
rv += $"exp: {exp.ToString()} k: {k} Pos: {kp.call_pos},{kp.put_pos} ({kp.call_raw_pos},{kp.put_raw_pos}) ";
}
}
}
if (cf_data.future_pos_map != null) {
foreach (var kv in cf_data.future_pos_map) {
rv += $"exp: {kv.Key.ToString()} {kv.Value.Item1},{kv.Value.Item2} ";
}
}
return rv;
}
internal static string log_string(this SlideFullData sl_data) {
Func<SlideGreekUnitKey, string> sguk_str = (sguk) => sguk.display_name;
Func<SlideGreekUnit, string> sgu_str = (sgu) => {
if (sgu == null)
return "No Handles";
string rv = $"Handle: {sgu.driver_price} ";
foreach (double d in sgu.position_greeks)
rv += $"{d}, ";
rv = rv.Trim();
if (rv.EndsWith(","))
rv = rv.TrimEnd(',');
return rv;
};
string rv = String.Empty;
foreach (var kv in sl_data.map) {
rv += $"SlideGreekUnitKey: {sguk_str(kv.Key)}\n";
foreach (var i_kv in kv.Value) {
rv += sgu_str(i_kv.Value) + "\n";
}
}
rv += $"Overriden?: {sl_data.ui_override != null}";
return rv;
}
internal static string log_string(this VolSurfaceUsageListImmutable vsu_list) {
string rv = "VolSurfaceUsageList:";
foreach (var u in vsu_list.UsageList) {
rv += $" {u.SecTup.Symbol}:{u.VsId}";
}
return rv;
}
internal static int tid() {
return System.Threading.Thread.CurrentThread.ManagedThreadId;
}
@@ -86,9 +86,14 @@ namespace mbts.spark {
}
private void _save_exp_params() {
var exp_params = new AnalyticsExpirationParameters[]{
new AnalyticsExpirationParameters(option_exp1, driver_exp, driver_exp, driver_exp, 0, 0, Double.NaN, 1, 1),
new AnalyticsExpirationParameters(option_exp2, driver_exp, driver_exp, driver_exp, 0, 0, Double.NaN, 1, 1),
var api_driver = new ExpirationDriverImmutable(new() {
Security = driver_exp.to_api_sec_exp()
});
var exp_params = new AnalyticsExpirationParameters[] {
new AnalyticsExpirationParameters(
option_exp1, api_driver, driver_exp, driver_exp, 0, 0, double.NaN, 1, 1),
new AnalyticsExpirationParameters(
option_exp2, api_driver, driver_exp, driver_exp, 0, 0, double.NaN, 1, 1),
};
_bb.post(SparkTags.ExpirationParametersCommitTag, exp_params);
}
@@ -103,4 +108,4 @@ namespace mbts.spark {
}
#endregion
}
}
}
@@ -31,11 +31,24 @@ namespace mbts.ui.controls {
VolSurfaceExpiration exp = p.Key;
VolCurveOutput exp_output = p.Value;
IDictionary<VolSurfaceDisplayGridColumn, object> out_exp_map = VolSurfaceUIAdapterUtils.get_exp_data(ref out_grid, exp);
out_exp_map[_fwd_col] = exp_output == null ? Double.NaN : exp_output.fwd;
out_exp_map[_ref_fwd_col] = exp_output != null && exp_output.adjusted_curve_parameters != null && exp_output.adjusted_curve_parameters.core_parameters != null ?
exp_output.adjusted_curve_parameters.core_parameters.ref_forward : Double.NaN;
out_exp_map[_live_driver_col] = (exp_output != null && exp_output.aux_data != null) ? exp_output.aux_data.driver_price : Double.NaN;
out_exp_map[_driver_override_col] = exp_output.adjusted_curve_parameters.core_parameters.driver_override;
out_exp_map[_fwd_col] = exp_output?.fwd ?? double.NaN;
out_exp_map[_ref_fwd_col] = exp_output
?.adjusted_curve_parameters
?.core_parameters
?.ref_forward
?? double.NaN;
out_exp_map[_live_driver_col] = exp_output
?.aux_data
?.driver_price
?? double.NaN;
out_exp_map[_driver_override_col] = exp_output
?.adjusted_curve_parameters
?.core_parameters
?.driver_override
?? double.NaN;
}
}
@@ -3,10 +3,11 @@ namespace mbts.spark {
using mbts.ui;
using mbts.ui.controls.graph;
using mbts.ui.shell;
using ProtoBuf;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
@@ -110,7 +111,7 @@ namespace mbts.spark {
//}
public object Clone() =>
ProtoBufSerializationHelper.clone_protobuf(this);
ProtobufSerializationHelper.clone(this);
public bool Equals(VolSurfaceGraphSettings other) =>
other != null &&
@@ -46,7 +46,9 @@ namespace mbts.spark {
if (startup_data.vol_curve_x_axis == null) {
var x_axis = BTSOxyGraphAxisDouble.Default;
x_axis.name = "Strike";
x_axis.axis_line_color = BTSColors.Graph.axis_line;
x_axis.major_grid_line_color = BTSColors.Graph.grid_line;
x_axis.tick_line_color = BTSColors.Graph.tick_line;
x_axis.position = AxisPosition.BottomLeftToRight;
x_axis.minimum = 0;
x_axis.maximum = 2000;
@@ -58,7 +60,9 @@ namespace mbts.spark {
if (startup_data.vol_curve_y_axis == null) {
var y_axis = BTSOxyGraphAxisDouble.Default;
y_axis.name = "Volatility";
y_axis.axis_line_color = BTSColors.Graph.axis_line;
y_axis.major_grid_line_color = BTSColors.Graph.grid_line;
y_axis.tick_line_color = BTSColors.Graph.tick_line;
y_axis.position = AxisPosition.LeftBottomToTop;
y_axis.minimum = 0;
y_axis.maximum = 1;
@@ -26,7 +26,7 @@ namespace mbts.spark.VolSurface {
id = key ?? throw new InvalidOperationException("Column key cannot be null");
}
public VolSurfaceDisplayGridColumn model { get; set; }
public VolSurfaceDisplayGridColumn model { get; }
public VolSurfaceColumnType type => model.type;
public new VolSurfaceColumnSettings create() {
@@ -43,7 +43,7 @@ namespace mbts.spark.VolSurface {
static Thickness _header_cell_padding => new(6, 0, 4, 0);
IValueConverter _data_context_converter =>
ValueConverter.create<VolSurfaceRowContext, object>(row => row?.get_cell(model));
ValueConverter.create<VolSurfaceRowVM, object>(row => row?.get_cell(model));
public override FrameworkElement view_factory() {
return type switch {
@@ -58,7 +58,7 @@ namespace mbts.spark.VolSurface {
HorizontalAlignment = HorizontalAlignment.Left,
Foreground = BTSColors.header_text.to_brush(),
};
text.SetBinding(TextBlock.TextProperty, new Binding(nameof(VolSurfaceRowContext.expiration)));
text.SetBinding(TextBlock.TextProperty, new Binding(nameof(VolSurfaceRowVM.expiration)));
var bd = new Border {
HorizontalAlignment = HorizontalAlignment.Stretch,
Padding = _header_cell_padding,
@@ -73,7 +73,7 @@ namespace mbts.spark.VolSurface {
var view = new TextBlock {
HorizontalAlignment = HorizontalAlignment.Right,
Margin = _cell_padding,
Foreground = Brushes.Blue,
Foreground = BTSColors.VolSurfaceGrid.readonly_column_foreground
};
view.SetBinding(FrameworkElement.DataContextProperty, new Binding() {
Converter = _data_context_converter
@@ -1,4 +1,4 @@
namespace mbts.spark.VolSurface {
namespace mbts.spark.VolSurface {
using bts;
using bts.collections;
using bts.utils;
@@ -63,7 +63,7 @@
};
_dispose = Disposable.Create(
ObservableAutoWrapper.connect(_expirations, rows, exp => new VolSurfaceRowContext(this, exp), row => row.Dispose()),
ObservableAutoWrapper.connect(_expirations, rows, exp => new VolSurfaceRowVM(this, exp), row => row.Dispose()),
sorted_visible_rows.bind(visible_rows),
Disposable.Create(() => {
this.model.on_candidate_grid_change -= _on_grid_updated;
@@ -102,14 +102,14 @@
public IReadOnlyObservableCollection<DIYGrid.ColumnBase> columns =>
_columns_model.views_with_header_ro;
public ObservableCollection<VolSurfaceRowContext> rows { get; } = new();
public ObservableCollection<VolSurfaceRowContext> visible_rows { get; } = new();
public ObservableSortedCollection<VolSurfaceRowContext> sorted_visible_rows { get; } = new(_row_comparer);
public ObservableCollection<VolSurfaceRowVM> rows { get; } = new();
public ObservableCollection<VolSurfaceRowVM> visible_rows { get; } = new();
public ObservableSortedCollection<VolSurfaceRowVM> sorted_visible_rows { get; } = new(_row_comparer);
public bool any_masters_selected =>
selected_rows.select_display_exp().where_master().Any();
public IEnumerable<VolSurfaceRowContext> selected_rows =>
public IEnumerable<VolSurfaceRowVM> selected_rows =>
visible_rows.where_selected();
public IEnumerable<DIYGridSuperHeaderVM> super_headers =>
@@ -118,13 +118,13 @@
.Select(group => new DIYGridSuperHeaderVM(group.Key, group.Count(), collapsed_content: _short_header(group.Key)))
.ToList();
public ICommand main_settings_command => _parent.main_settings_command;
public ICommand advanced_settings_command => _parent.advanced_settings_command;
public ICommand graph_settings_command => _parent.vol_curve_vm.settings_command;
public ICommand grid_settings_command => _parent.grid_settings_command;
public ICommand main_settings_cmd => _parent.main_settings_cmd;
public ICommand advanced_settings_cmd => _parent.advanced_settings_cmd;
public ICommand graph_settings_cmd => _parent.vol_curve_vm.settings_command;
public ICommand grid_settings_cmd => _parent.grid_settings_cmd;
static IComparer<VolSurfaceRowContext> _row_comparer =>
Comparer<VolSurfaceDisplayGridExpiration>.Default.wrap<VolSurfaceDisplayGridExpiration, VolSurfaceRowContext>(r => r.expiration);
static IComparer<VolSurfaceRowVM> _row_comparer =>
Comparer<VolSurfaceDisplayGridExpiration>.Default.wrap<VolSurfaceDisplayGridExpiration, VolSurfaceRowVM>(r => r.expiration);
public void load_from(VolSurfaceMacroGridSettings grid_settings) {
_hidden_columns = new HashSet<string>(grid_settings.hidden_cols());
@@ -193,23 +193,23 @@
}
}
internal void copy_to_selection(VolSurfaceDisplayGridExpiration exp, VolSurfaceDisplayGridColumn column, GridColumnSet set) {
if (column.type == VolSurfaceColumnType.ReadWriteTick) {
_replicate(exp, selected_rows.select_display_exp().Except(exp), _get_columns(column, set));
}
}
internal void copy_to_selection(
VolSurfaceDisplayGridExpiration exp,
VolSurfaceDisplayGridColumn column,
GridColumnSet set) =>
_replicate(exp, selected_rows.select_display_exp().Except(exp), _get_columns(column, set));
internal void copy_to_masters(VolSurfaceDisplayGridExpiration exp, VolSurfaceDisplayGridColumn column, GridColumnSet set) {
if (column.type == VolSurfaceColumnType.ReadWriteTick) {
_replicate(exp, _expirations.where_master().Except(exp), _get_columns(column, set));
}
}
internal void copy_to_masters(
VolSurfaceDisplayGridExpiration exp,
VolSurfaceDisplayGridColumn column,
GridColumnSet set) =>
_replicate(exp, _expirations.where_master().Except(exp), _get_columns(column, set));
internal void copy_to_all(VolSurfaceDisplayGridExpiration exp, VolSurfaceDisplayGridColumn column, GridColumnSet set) {
if (column.type == VolSurfaceColumnType.ReadWriteTick) {
_replicate(exp, _expirations.Except(exp), _get_columns(column, set));
}
}
internal void copy_to_all(
VolSurfaceDisplayGridExpiration exp,
VolSurfaceDisplayGridColumn column,
GridColumnSet set) =>
_replicate(exp, _expirations.Except(exp), _get_columns(column, set));
static string _short_header(string header) =>
string.Join("", header.Where(Char.IsUpper));
@@ -299,7 +299,7 @@
VolSurfaceDisplayGridExpiration source,
IEnumerable<VolSurfaceDisplayGridExpiration> target_exps,
IEnumerable<VolSurfaceDisplayGridColumn> cols) {
foreach (var col in cols) {
foreach (var col in cols.Where(c => c.type.is_editable())) {
foreach (var exp in target_exps) {
_copy(source, exp, col);
}
@@ -307,7 +307,14 @@
_commit();
}
void _copy(VolSurfaceDisplayGridExpiration source, VolSurfaceDisplayGridExpiration dest, VolSurfaceDisplayGridColumn col) {
void _copy(
VolSurfaceDisplayGridExpiration source,
VolSurfaceDisplayGridExpiration dest,
VolSurfaceDisplayGridColumn col
) {
if (!col.type.is_editable()) {
throw new ArgumentException("Expected col to be editable", nameof(col));
}
if (current_grid.read(source, col, out var value)) {
current_grid.set_grid_data(dest, col.unique_col_name, value);
}
@@ -1,335 +0,0 @@
namespace mbts.spark.VolSurface {
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.shell;
using mbts.ui.utility;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Windows.Input;
using System.Windows.Media;
public struct VolSurfaceCellState {
public bool is_dirty => committed_text != null;
public FormattedText text;
public FormattedText committed_text;
}
class VolSurfaceRowContext : DisposableViewModelBase, ISelectable, IFormatCellsToClipboard, DIYGrid.IRowVM {
readonly VolSurfaceGridVM _parent;
readonly VolSurfaceDisplayGridExpiration _exp;
/// TODO: remove _text_cache when we are sure that the new row view
/// (<see cref="VolSurfaceRowView"/>) is solid. It must remain in place
/// until then, as it is used by old row view
/// (<see cref="VolSurfaceRowControl"/>).
readonly Dictionary<string, CellData> _cells = new();
MenuContext _context_menu;
bool _is_selected;
public VolSurfaceRowContext(VolSurfaceGridVM parent, VolSurfaceDisplayGridExpiration exp) {
_parent = parent;
_exp = exp;
_dispose = Disposable.Create(() => {
_cells.Values.DisposeAll();
_cells.Clear();
});
}
public event Action<bool> is_selected_changed;
public event Action invalidated;
public VolSurfaceDisplayGridExpiration expiration => _exp;
public bool is_selected {
get => _is_selected;
set {
if (_is_selected != value) {
_is_selected = value;
is_selected_changed?.Invoke(value);
_parent.signal_selection_changed();
}
}
}
public MenuContext context_menu =>
_context_menu ??= new(_parent, this);
public VolGridCellVM get_cell(VolSurfaceDisplayGridColumn column) {
if (!_cells.TryGetValue(column.unique_col_name, out var cell_data)) {
_cells.Add(column.unique_col_name, cell_data = _create_cell(column));
}
return cell_data.vm;
}
public void invalidate() {
foreach (var cell in _cells.Values) {
_sync_cell(cell.vm);
}
raise_invalidated();
}
public override string ToString() =>
_exp.ToString();
public string[] get_cell_clipboard_strings() =>
new[] { _exp.ToString() }.Concat(
_parent.columns.OfType<VolSurfaceColumn>()
.Skip(1)
.Select(c => {
var val = _parent.current_grid.read(_exp, c.model.unique_col_name);
return c.model.format(val);
}))
.ToArray();
public void raise_invalidated() =>
invalidated?.Invoke();
CellData _create_cell(VolSurfaceDisplayGridColumn column) {
var cell = column.type switch {
VolSurfaceColumnType.ReadWriteTick => create_tick_cell(),
_ => new VolGridCellVM(column.unique_col_name),
};
_sync_cell(cell);
var dispose = cell.observe_candidate().DistinctUntilChanged().OnDispatcher().Subscribe(value => {
var curr = _parent.current_grid.read(expiration, column);
if (Equals(value, curr)) {
return;
}
var grid = _parent.current_grid;
grid.write(expiration, column, value);
_parent.model.set_candidate_grid(grid);
});
return new(cell, dispose);
VolGridTickCellVM create_tick_cell() {
var cell = new VolGridTickCellVM(column.unique_col_name);
cell.request_tick += is_up => {
var col = _parent.get_column(column.unique_col_name);
if (col is null) {
throw new InvalidOperationException($"Failed to find column with id {column.unique_col_name}");
}
if (col.model?.tick_move is var tm) {
cell.candidate_value = tm(cell.candidate_value, is_up);
return;
}
throw new InvalidOperationException($"tick_move is not defined");
};
return cell;
}
}
void _sync_cell(VolGridCellVM cell) {
if (cell is null) {
return;
}
cell.committed_value = _parent.committed_grid.read(_exp, cell.column_id);
cell.candidate_value = _parent.current_grid.read(_exp, cell.column_id);
}
public class MenuContext : ViewModelBase {
readonly VolSurfaceRowContext _row;
readonly VolSurfaceGridVM _parent;
VolSurfaceColumn _col;
DIYGridSuperHeaderVM _supercol;
ICommand _revert_command;
ICommand _shift_selection_command;
ICommand _shift_masters_command;
ICommand _shift_all_command;
ICommand _clear_command;
ICommand _copy_to_selection_command;
ICommand _copy_to_masters_command;
ICommand _copy_to_all_command;
ICommand _copy_all_to_clipboard_command;
ICommand _smart_copy_rolls_rates_command;
ICommand _import_csv_command;
public MenuContext(
VolSurfaceGridVM parent,
VolSurfaceRowContext row) {
_parent = parent;
_row = row;
}
public string column_name => _col.model.display_name;
public string group_name => _supercol.id;
public string expiration_name => _row.ToString();
public VolSurfaceColumn column {
get => _col;
set => Set(ref _col, value);
}
public DIYGridSuperHeaderVM super_header {
get => _supercol;
set => Set(ref _supercol, value);
}
public VolSurfaceDisplayGridExpiration expiration => _row.expiration;
public class SymbolFilter {
readonly MenuContext _context;
bool? _visible;
public SymbolFilter(MenuContext context, string symbol, int count, int visible_count) {
_context = context;
this.symbol = symbol;
if (count == visible_count) {
_visible = true;
} else if (visible_count == 0) {
_visible = false;
} else {
_visible = null;
}
}
public string symbol { get; private set; }
public bool? visible {
get => _visible;
set {
_visible = value;
if (value == true) {
_context._show_symbol(symbol);
} else if (value == false) {
_context._hide_symbol(symbol);
}
}
}
}
public IEnumerable<SymbolFilter> symbols {
get {
var visible_exps = _parent.visible_rows
.Cast<VolSurfaceRowContext>()
.GroupBy(r => r._exp.symbol)
.ToDictionary(g => g.Key);
var result = _parent.rows
.GroupBy(r => r._exp.symbol)
.OrderBy(g => g.Key)
.Select(g => new SymbolFilter(this, g.Key, g.Count(), visible_exps.ContainsKey(g.Key) ? visible_exps[g.Key].Count() : 0));
return result;
}
}
public bool is_input_cell => _col.type == VolSurfaceColumnType.ReadWriteTick;
public ICommand main_settings_command => _parent.main_settings_command;
public ICommand advanced_settings_command => _parent.advanced_settings_command;
public ICommand grid_settings_command => _parent.grid_settings_command;
public ICommand graph_settings_command => _parent.graph_settings_command;
public ICommand revert_command =>
_revert_command ??= new DelegateCommand(_ => _row.get_cell(_col.model)?.revert());
public ICommand shift_selection_command =>
_shift_selection_command ??= new DelegateCommand(() => {
if (_col.model.type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_selection(_col.model);
}
}, () => _col.model.type == VolSurfaceColumnType.ReadWriteTick);
public ICommand shift_masters_command =>
_shift_masters_command ??= new DelegateCommand(() => {
if (_col.model.type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_masters(_col.model);
}
}, () => _col.model.type == VolSurfaceColumnType.ReadWriteTick);
public ICommand shift_all_command =>
_shift_all_command ??= new DelegateCommand(() => {
if (_col.model.type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_all(_col.model);
}
}, () => _col.model.type == VolSurfaceColumnType.ReadWriteTick);
public ICommand clear_command =>
_clear_command ??= new DelegateCommand<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.clear(_col.model, gc);
}
},
_has_editable_cells);
public ICommand copy_to_selection_command =>
_copy_to_selection_command ??= new DelegateCommand<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_selection(expiration, _col.model, gc);
}
},
_has_editable_cells);
public ICommand copy_to_masters_command =>
_copy_to_masters_command ??= new DelegateCommand<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_masters(expiration, _col.model, gc);
}
},
_has_editable_cells);
public ICommand copy_to_all_command =>
_copy_to_all_command ??= new DelegateCommand<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_all(expiration, _col.model, gc);
}
},
_has_editable_cells);
public ICommand copy_all_to_clipboard_command =>
_copy_all_to_clipboard_command ??= new DelegateCommand(() => {
string clipboard_text = ClipboardHelper.GetExcelFormattedText(
_parent.visible_rows
.OfType<VolSurfaceRowContext>()
.Select(r => r.get_cell_clipboard_strings())
.Where(cells => cells != null));
if (!clipboard_text.is_null_or_empty()) {
ClipboardHelper.CopyTextToClipboard(clipboard_text);
}
});
public ICommand smart_copy_rolls_rates_command =>
_smart_copy_rolls_rates_command ??= new DelegateCommand(_ => _parent.model.sync_slave_ref_forwards(expiration.ToVSExp()));
public ICommand import_csv_command =>
_import_csv_command ??= FileDialogCommand.open_file(
_parent.model.import_csv_file,
() => _parent.model.csv_importing_enabled(),
null);
bool _has_editable_cells(string where) =>
!Enum.TryParse(where, out GridColumnSet gc) ||
gc == GridColumnSet.Column || _col.model.type != VolSurfaceColumnType.ReadOnly;
void _hide_symbol(string symbol) {
_parent.visible_rows.RemoveAll(s => ((VolSurfaceRowContext)s).expiration.symbol == symbol);
_parent.signal_selection_changed();
}
void _show_symbol(string symbol) {
// Insert items from rows to visible_Rows that have symbol=true in sorted order
// do this by making the desired collection and then leveraging sync_with
var visible = new HashSet<VolSurfaceDisplayGridExpiration>(_parent.visible_rows.Cast<VolSurfaceRowContext>().Select(row => row.expiration));
var desired = _parent.rows.Where(row => row.expiration.symbol == symbol || visible.Contains(row.expiration));
_parent.visible_rows.sync_with(desired);
}
}
class CellData : IDisposable {
IDisposable _dispose;
VolGridCellVM _vm;
public CellData(VolGridCellVM vm, IDisposable dispose) {
_vm = vm;
_dispose = dispose;
}
public VolGridCellVM vm => _vm;
public void Dispose() {
Disposable.dispose(ref _vm);
Disposable.dispose(ref _dispose);
}
}
}
}
@@ -0,0 +1,217 @@
#nullable enable
namespace mbts.spark {
using bts.collections;
using mbts.spark.VolSurface;
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.shell;
using mbts.ui.utility;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Windows.Input;
class VolSurfaceRowContextMenuVM : DisposableViewModelBase {
readonly VolSurfaceRowVM _row;
readonly VolSurfaceGridVM _parent;
readonly Property<VolSurfaceColumn?> _column;
readonly Property<DIYGridSuperHeaderVM?> _super_header;
ICommand? _revert_cmd;
ICommand? _shift_selection_cmd;
ICommand? _shift_masters_cmd;
ICommand? _shift_all_cmd;
ICommand? _clear_cmd;
ICommand? _copy_to_selection_cmd;
ICommand? _copy_to_masters_cmd;
ICommand? _copy_to_all_cmd;
ICommand? _copy_all_to_clipboard_cmd;
ICommand? _smart_copy_rolls_rates_cmd;
ICommand? _import_csv_cmd;
public VolSurfaceRowContextMenuVM(VolSurfaceGridVM parent, VolSurfaceRowVM row) {
_parent = parent;
_row = row;
_column = backing<VolSurfaceColumn?>(nameof(column));
_super_header = backing<DIYGridSuperHeaderVM?>(nameof(super_header));
_dispose = Disposable.Create(
_column.invalidate_others_on_change(nameof(column_name)),
_super_header.invalidate_others_on_change(nameof(group_name)),
_parent.visible_rows.ObserveSelf()
.BufferLatest(TimeSpan.FromSeconds(1))
.OnDispatcher()
.Subscribe(_ => sync_symbols()));
void sync_symbols() {
var visible_exps = _parent.visible_rows.Map(r => r.expiration.symbol);
symbols.sync_with_models(
visible_exps,
kv => new SymbolItemVM(this, kv.Key),
(svm, kv) => {
svm.symbol = kv.Key;
svm.visible = SelectAllToggle.is_all_selected(
visible_exps[svm.symbol].Count(),
kv.Value.Count());
return svm;
});
}
}
public string column_name => column?.model?.display_name ?? string.Empty;
public string group_name => super_header?.id ?? string.Empty;
public string expiration_name => _row.ToString();
public VolSurfaceColumn? column {
get => _column.Value;
set => _column.set(value);
}
public DIYGridSuperHeaderVM? super_header {
get => _super_header.Value;
set => _super_header.set(value);
}
public VolSurfaceDisplayGridExpiration expiration => _row.expiration;
public ObservableCollection<SymbolItemVM> symbols { get; } = new();
public bool is_input_cell => column?.type == VolSurfaceColumnType.ReadWriteTick;
public ICommand main_settings_cmd => _parent.main_settings_cmd;
public ICommand advanced_settings_cmd => _parent.advanced_settings_cmd;
public ICommand grid_settings_cmd => _parent.grid_settings_cmd;
public ICommand graph_settings_cmd => _parent.graph_settings_cmd;
public ICommand revert_cmd =>
_revert_cmd ??= new Command(_ => {
_row.get_cell(_assert_model())?.revert();
});
public ICommand shift_selection_cmd =>
_shift_selection_cmd ??= new Command(() => {
if (_assert_model().type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_selection(_assert_model());
}
}, () => _assert_model().type == VolSurfaceColumnType.ReadWriteTick);
public ICommand shift_masters_cmd =>
_shift_masters_cmd ??= new Command(() => {
if (_assert_model().type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_masters(_assert_model());
}
}, () => _assert_model().type == VolSurfaceColumnType.ReadWriteTick);
public ICommand shift_all_cmd =>
_shift_all_cmd ??= new Command(() => {
if (_assert_model().type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_all(_assert_model());
}
}, () => _assert_model().type == VolSurfaceColumnType.ReadWriteTick);
public ICommand clear_cmd =>
_clear_cmd ??= new Command<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.clear(_assert_model(), gc);
}
},
_has_editable_cells);
public ICommand copy_to_selection_cmd =>
_copy_to_selection_cmd ??= new Command<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_selection(expiration, _assert_model(), gc);
}
});
public ICommand copy_to_masters_cmd =>
_copy_to_masters_cmd ??= new Command<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_masters(expiration, _assert_model(), gc);
}
});
public ICommand copy_to_all_cmd =>
_copy_to_all_cmd ??= new Command<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_all(expiration, _assert_model(), gc);
}
});
public ICommand copy_all_to_clipboard_cmd =>
_copy_all_to_clipboard_cmd ??= new Command(() => {
string clipboard_text = ClipboardHelper.GetExcelFormattedText(
_parent.visible_rows
.OfType<VolSurfaceRowVM>()
.Select(r => r.get_cell_clipboard_strings())
.Where(cells => cells != null));
if (!clipboard_text.is_null_or_empty()) {
ClipboardHelper.CopyTextToClipboard(clipboard_text);
}
});
public ICommand smart_copy_rolls_rates_cmd =>
_smart_copy_rolls_rates_cmd ??= new Command(
() => _parent.model.sync_slave_ref_forwards(expiration.ToVSExp()));
public ICommand import_csv_cmd =>
_import_csv_cmd ??= FileDialogCommand.open_file(
_parent.model.import_csv_file,
_parent.model.csv_importing_enabled,
null);
VolSurfaceDisplayGridColumn _assert_model() =>
column?.model ?? throw new InvalidOperationException();
bool _has_editable_cells(string where) =>
!Enum.TryParse(where, out GridColumnSet gc) ||
gc == GridColumnSet.Column || _assert_model().type != VolSurfaceColumnType.ReadOnly;
void _hide_symbol(string symbol) {
_parent.visible_rows.RemoveAll(s => s.expiration.symbol == symbol);
_parent.signal_selection_changed();
}
void _show_symbol(string symbol) {
// Insert items from rows to visible_Rows that have symbol=true in sorted order
// do this by making the desired collection and then leveraging sync_with
var visible = _parent.visible_rows
.Select(row => row.expiration)
.ToHashSet();
var desired = _parent.rows.Where(
row => row.expiration.symbol == symbol || visible.Contains(row.expiration));
_parent.visible_rows.sync_with(desired);
}
public class SymbolItemVM : ViewModelBase {
readonly VolSurfaceRowContextMenuVM _context;
string _symbol;
bool? _visible;
public SymbolItemVM(
VolSurfaceRowContextMenuVM context, string symbol) {
_context = context;
_symbol = symbol;
}
public string symbol {
get => _symbol;
set => Set(ref _symbol, value);
}
public bool? visible {
get => _visible;
set {
if (Set(ref _visible, value)) {
if (value is true) {
_context._show_symbol(symbol);
} else if (value is false) {
_context._hide_symbol(symbol);
}
}
}
}
}
}
}
@@ -1,372 +0,0 @@
// using mbts;
// using mbts.ui;
// using mbts.ui.controls;
// using mbts.ui.dpi;
// using mbts.ui.utility.text;
// using System;
// using System.Collections.Generic;
// using System.Diagnostics;
// using System.Globalization;
// using System.Linq;
// using System.Text;
// using System.Threading.Tasks;
// using System.Windows;
// using System.Windows.Controls;
// using System.Windows.Input;
// using System.Windows.Media;
// namespace mbts.spark.VolSurface {
// class VolSurfaceRowControl : DIYGrid.HighPerformanceRow<VolSurfaceRowContext> {
// FormattedText _exp_text;
// readonly double _padding = 5.0;
// readonly Pen _dirty_pen = new Pen(Brushes.Red, 1.0);
// readonly Pen _selection_pen = new Pen(Brushes.Black, 1.0) { DashStyle = DashStyles.Dot };
// TickUpDown _cell_editor_backing;
// TickUpDown _cell_editor => _cell_editor_backing ??= new ();
// int? _selected_cell;
// public VolSurfaceRowControl() {
// Loaded += (s, e) => ContextMenu = TryFindResource("context_menu") as ContextMenu;
// GotKeyboardFocus += (s, e) => {
// if (e.OriginalSource is not FrameworkElement el) {
// return;
// }
// var cell_tl = el.TranslatePoint(new Point(0, 0), this);
// _on_focus_move(DIYGrid.RowUtils.column_at(_column_layout, cell_tl));
// };
// }
// int? _column_index(DIYGrid.ColumnGeometry col) =>
// _column_layout.TryGetFirst(c => c.Equals(col), out var _, out var idx) ? idx : null;
// //private static int _render_count = 0;
// protected override void OnRender(DrawingContext dc) {
// // Fill with transparent for hit testing
// dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, new Rect(0, 0, _column_layout.Sum(c => c.width), RenderSize.Height));
// string last_group = "";
// foreach (var cell in _column_layout) {
// // Render collapsed columns
// if (cell.column.is_collapsed) {
// dc.DrawRectangle(BTSColors.AW2.collapsed, null, new Rect(cell.left, 0, cell.width, Height));
// continue;
// }
// var column = (VolSurfaceSimplifiedColumn)cell.column;
// VolSurfaceCellState celldata;
// // Get the cell text
// if (column.type == VolSurfaceSimplifiedColumnType.RowHeader) {
// // Fill in this one
// dc.DrawRectangle(BTSColors.header, null, new Rect(cell.left, 0, cell.width, Height));
// var exp = _row.expiration;
// if (_exp_text == null) {
// _exp_text = format_text(exp.ToString(), exp.is_slave ? Brushes.LightGray : Brushes.White);
// }
// celldata = new VolSurfaceCellState() {
// text = _exp_text
// };
// } else if (column.type == VolSurfaceSimplifiedColumnType.ReadOnly) {
// celldata = _row.get_value(column.volsurface_column, format(Brushes.Blue), _ => null);
// } else {
// celldata = _row.get_value(column.volsurface_column, format(Brushes.Black), format(Brushes.DarkGray));
// }
// // If the cell is partly hidden clip the draw
// if (cell.is_partially_obscured) {
// dc.PushClip(new RectangleGeometry(
// new Rect(cell.left, 0, cell.width, Height)));
// }
// // draw text centered vertially
// double total_width = _padding + celldata.text.Width;
// double pad_top = (Height - celldata.text.Height) / 2.0;
// dc.DrawText(celldata.text, new Point(cell.unclipped_left + _padding, pad_top));
// if (celldata.committed_text != null) {
// pad_top = (Height - celldata.committed_text.Height) / 2.0;
// dc.DrawText(celldata.committed_text, new Point(cell.unclipped_left + total_width, pad_top));
// total_width += celldata.committed_text.Width;
// }
// // draw grid lines
// double line_width; Brush fill;
// if (last_group == cell.group) { line_width = 1; fill = _grid.VerticalGridLineBrush; } else { line_width = 2; fill = _grid.VerticalGroupSeparatorBrush; }
// dc.DrawRectangle(fill, null, new Rect(cell.left - line_width, 0, line_width, Height));
// Rect cell_border_rect = new Rect(cell.unclipped_left + 1, 0, Math.Max(0, cell.width - (line_width * 2)), Height - 1);
// // draw dirty rect
// if (celldata.is_dirty) {
// dc.DrawRectangle(null, _dirty_pen, cell_border_rect);
// }
// // Draw selection
// if (_selected_cell == _column_index(cell) && column.type != VolSurfaceSimplifiedColumnType.ReadWriteTick) {
// dc.DrawRectangle(null, _selection_pen, cell_border_rect);
// }
// if (cell.is_partially_obscured) { dc.Pop(); }
// total_width += _padding;//right padding
// if (!celldata.is_dirty && column.type == VolSurfaceSimplifiedColumnType.ReadWriteTick) total_width += 22; // size of buttons on a tickupdown
// if (total_width > cell.width) {
// Dispatcher.BeginInvoke(((Action)(() => cell.column.Width = total_width)));
// }
// last_group = cell.group;
// }
// if (_selected_cell != NO_CELL) {
// if (_cell_editor.Visibility == Visibility.Visible) {
// var position = _column_geometry[_selected_cell];
// PositionControlOver(tud, position);
// }
// }
// //++_render_count;
// //dc.DrawText(
// // format_text(_render_count.ToString(), Brushes.Black),
// // new Point(0, 0));
// }
// Func<string, FormattedText> format(Brush brush) =>
// str => format_text(str, brush);
// void _on_focus_move(DIYGrid.ColumnGeometry? new_column) {
// if (new_column != null) {
// enable_edit(new_column.Value);
// }
// InvalidateVisual();
// }
// private async void enable_edit(DIYGrid.ColumnGeometry column) {
// await Task.Yield();
// var col = (VolSurfaceSimplifiedColumn)column.column;
// var tud = _grid.get_edit_control<TickUpDown>();
// if (col.type == VolSurfaceSimplifiedColumnType.ReadWriteTick) {
// tud.DataContext = _row.get_edit_context(col.volsurface_column);
// PositionControlOver(tud, column);
// var fe = tud.Content as TextBox;
// if (fe != null) {
// await Task.Yield();
// fe.Focus();
// fe.SelectAll();
// }
// } else {
// tud.DataContext = null;
// tud.Visibility = Visibility.Collapsed;
// var item = this.find_ancestor_of_type<ListBoxItem>();
// if (item != null) {
// item.Focus();
// }
// }
// }
// protected override void OnMouseRightButtonUp(MouseButtonEventArgs e) {
// // _grid.column
// var cell = DIYGrid.RowUtils.column_at(_column_layout, e.GetPosition(this));
// if (ContextMenu != null) {
// if (cell.HasValue && DIYGrid.RowUtils.column_index(_column_layout, cell.Value) > (_grid.FrozenColumnCount - 1)) {
// ContextMenu.DataContext = _row.get_context_menu_context((VolSurfaceSimplifiedColumn)cell.Value.column, cell.Value.super_column);
// } else {
// e.Handled = true;
// ContextMenu.DataContext = null;
// }
// }
// base.OnMouseRightButtonDown(e);
// }
// FormattedText format_text(string content, Brush fg) {
// var ft = new FormattedText(content, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
// TextUtils.StandardTypeface, FontSizes.Regular, Brushes.Black, HighDpiExtensions.dpi_ratio);
// return ft;
// }
// }
// }
// using mbts;
// using mbts.ui;
// using mbts.ui.controls;
// using mbts.ui.dpi;
// using mbts.ui.utility.text;
// using System;
// using System.Collections.Generic;
// using System.Diagnostics;
// using System.Globalization;
// using System.Linq;
// using System.Text;
// using System.Threading.Tasks;
// using System.Windows;
// using System.Windows.Controls;
// using System.Windows.Input;
// using System.Windows.Media;
// namespace mbts.spark.VolSurface {
// class VolSurfaceRowControl : DIYGrid.RowBase {
// VolSurfaceRowContext _row;
// FormattedText _exp_text;
// readonly double _padding = 5.0;
// readonly Pen _dirty_pen = new Pen(Brushes.Red, 1.0);
// readonly Pen _selection_pen = new Pen(Brushes.Black, 1.0) { DashStyle = DashStyles.Dot };
// public VolSurfaceRowControl() {
// DataContextChanged += OnDataContextChanged;
// Loaded += OnLoaded;
// }
// #region SelectedCell
// public static readonly DependencyProperty SelectedCellProperty =
// WPFHelper.create_dp<object, VolSurfaceRowControl>(nameof(SelectedCell));
// public object SelectedCell {
// get => GetValue(SelectedCellProperty);
// set => SetValue(SelectedCellProperty, value);
// }
// #endregion
// void OnLoaded(object sender, RoutedEventArgs e) {
// ContextMenu = TryFindResource("context_menu") as ContextMenu;
// }
// void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e) {
// var oldrow = e.OldValue as VolSurfaceRowContext;
// if (oldrow != null) {
// oldrow.on_invalidate -= InvalidateVisual;
// }
// _row = DataContext as VolSurfaceRowContext;
// _row.on_invalidate += InvalidateVisual;
// }
// //private static int _render_count = 0;
// protected override void OnRender(DrawingContext dc) {
// if (_grid == null) return;
// // Fill with transparent for hit testing
// dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, new Rect(0, 0, _column_geometry.Sum(g => g.width), RenderSize.Height));
// string last_group = "";
// foreach (var cell in _column_geometry) {
// // Render collapsed columns
// if (cell.column.is_collapsed) {
// dc.DrawRectangle(BTSColors.AW2.collapsed, null, new Rect(cell.left, 0, cell.width, Height));
// continue;
// }
// var column = (VolSurfaceSimplifiedColumn)cell.column;
// VolSurfaceCellState celldata;
// // Get the cell text
// if (column.type == VolSurfaceSimplifiedColumnType.RowHeader) {
// // Fill in this one
// dc.DrawRectangle(BTSColors.header, null, new Rect(cell.left, 0, cell.width, Height));
// var exp = _row.expiration;
// if (_exp_text == null) {
// _exp_text = format_text(exp.ToString(), exp.is_slave ? Brushes.LightGray : Brushes.White);
// }
// celldata = new VolSurfaceCellState() { text = _exp_text };
// } else if (column.type == VolSurfaceSimplifiedColumnType.ReadOnly) {
// celldata = _row.get_value(column.volsurface_column, format(Brushes.Blue), _ => null);
// } else {
// celldata = _row.get_value(column.volsurface_column, format(Brushes.Black), format(Brushes.DarkGray));
// }
// // If the cell is partly hidden clip the draw
// if (cell.is_partially_obscured) {
// dc.PushClip(new RectangleGeometry(
// new Rect(cell.left, 0, cell.width, Height)));
// }
// // draw text centered vertially
// double total_width = _padding + celldata.text.Width;
// double pad_top = (Height - celldata.text.Height) / 2.0;
// dc.DrawText(celldata.text, new Point(cell.unclipped_left + _padding, pad_top));
// if (celldata.committed_text != null) {
// pad_top = (Height - celldata.committed_text.Height) / 2.0;
// dc.DrawText(celldata.committed_text, new Point(cell.unclipped_left + total_width, pad_top));
// total_width += celldata.committed_text.Width;
// }
// // draw grid lines
// double line_width; Brush fill;
// if (last_group == cell.group) { line_width = 1; fill = _grid.VerticalGridLineBrush; } else { line_width = 2; fill = _grid.VerticalGroupSeparatorBrush; }
// dc.DrawRectangle(fill, null, new Rect(cell.left - line_width, 0, line_width, Height));
// Rect cell_border_rect = new Rect(cell.unclipped_left + 1, 0, Math.Max(0, cell.width - (line_width * 2)), Height - 1);
// // draw dirty rect
// if (celldata.is_dirty) {
// dc.DrawRectangle(null, _dirty_pen, cell_border_rect);
// }
// // Draw selection
// if (_selected_cell == column_index(cell) && column.type != VolSurfaceSimplifiedColumnType.ReadWriteTick) {
// dc.DrawRectangle(null, _selection_pen, cell_border_rect);
// }
// if (cell.is_partially_obscured) { dc.Pop(); }
// total_width += _padding;//right padding
// if (!celldata.is_dirty && column.type == VolSurfaceSimplifiedColumnType.ReadWriteTick) total_width += 22; // size of buttons on a tickupdown
// if (total_width > cell.width) {
// Dispatcher.BeginInvoke(((Action)(() => cell.column.Width = total_width)));
// }
// last_group = cell.group;
// }
// //++_render_count;
// //dc.DrawText(
// // format_text(_render_count.ToString(), Brushes.Black),
// // new Point(0, 0));
// }
// private Func<string, FormattedText> format(Brush brush) {
// return str => format_text(str, brush);
// }
// protected override void OnClick(DIYGrid.ColumnGeometry column) {
// }
// protected override void OnFocusMove(DIYGrid.ColumnGeometry? new_column) {
// if (new_column != null) enable_edit(new_column.Value);
// InvalidateVisual();
// }
// private async void enable_edit(DIYGrid.ColumnGeometry column) {
// await Task.Yield();
// var col = (VolSurfaceSimplifiedColumn)column.column;
// var tud = _grid.get_edit_control<TickUpDown>();
// if (col.type == VolSurfaceSimplifiedColumnType.ReadWriteTick) {
// tud.DataContext = _row.get_edit_context(col.volsurface_column);
// PositionControlOver(tud, column);
// var fe = tud.Content as TextBox;
// if (fe != null) {
// await Task.Yield();
// fe.Focus();
// fe.SelectAll();
// }
// } else {
// tud.DataContext = null;
// tud.Visibility = Visibility.Collapsed;
// var item = this.find_ancestor_of_type<ListBoxItem>();
// if (item != null) {
// item.Focus();
// }
// }
// }
// protected override void OnMouseRightButtonUp(MouseButtonEventArgs e) {
// var cell = column_at(e.GetPosition(this));
// if (ContextMenu != null) {
// if (cell.HasValue && column_index(cell.Value) > (_grid.FrozenColumnCount - 1)) {
// ContextMenu.DataContext = _row.get_context_menu_context((VolSurfaceSimplifiedColumn)cell.Value.column, cell.Value.super_column);
// } else {
// e.Handled = true;
// ContextMenu.DataContext = null;
// }
// }
// base.OnMouseRightButtonDown(e);
// }
// FormattedText format_text(string content, Brush fg) {
// var ft = new FormattedText(content, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
// TextUtils.StandardTypeface, FontSizes.Regular, Brushes.Black, HighDpiExtensions.dpi_ratio);
// return ft;
// }
// }
// }
@@ -0,0 +1,137 @@
#nullable enable
namespace mbts.spark.VolSurface {
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.shell;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Windows.Media;
public struct VolSurfaceCellState {
public bool is_dirty => committed_text is not null;
public FormattedText? text;
public FormattedText? committed_text;
}
class VolSurfaceRowVM : DisposableViewModelBase, ISelectable, IFormatCellsToClipboard, DIYGrid.IRowVM {
readonly VolSurfaceGridVM _parent;
readonly VolSurfaceDisplayGridExpiration _exp;
readonly Dictionary<string, CellData> _cells = new();
VolSurfaceRowContextMenuVM? _context_menu;
bool _is_selected;
public VolSurfaceRowVM(VolSurfaceGridVM parent, VolSurfaceDisplayGridExpiration exp) {
_parent = parent;
_exp = exp;
_dispose = Disposable.Create(() => {
_cells.Values.DisposeAll();
_cells.Clear();
_context_menu?.Dispose();
});
}
public event Action<bool>? is_selected_changed;
public event Action? invalidated;
public VolSurfaceDisplayGridExpiration expiration => _exp;
public bool is_selected {
get => _is_selected;
set {
if (Set(ref _is_selected, value)) {
is_selected_changed?.Invoke(value);
_parent.signal_selection_changed();
}
}
}
public VolSurfaceRowContextMenuVM context_menu =>
_context_menu ??= new(_parent, this);
public VolGridCellVM get_cell(VolSurfaceDisplayGridColumn column) =>
_cells.GetOrAdd(column.unique_col_name, _ => _create_cell(column)).vm;
public void invalidate() {
foreach (var cell in _cells.Values) {
_sync_cell(cell.vm);
}
invalidated?.Invoke();
}
public string[] get_cell_clipboard_strings() =>
new[] { _exp.ToString() }.Concat(
_parent.columns.OfType<VolSurfaceColumn>().Skip(1).Select(c => {
var val = _parent.current_grid.read(_exp, c.model.unique_col_name);
return c.model.format(val);
}))
.ToArray();
public override string ToString() =>
_exp.ToString();
void DIYGrid.IRowVM.raise_invalidated() =>
invalidated?.Invoke();
CellData _create_cell(VolSurfaceDisplayGridColumn column) {
var cell = column.type switch {
VolSurfaceColumnType.ReadWriteTick => create_tick_cell(),
_ => new VolGridCellVM(column.unique_col_name),
};
_sync_cell(cell);
var dispose = cell.observe_candidate().DistinctUntilChanged().OnDispatcher()
.Subscribe(value => {
var curr = _parent.current_grid.read(expiration, column);
if (Equals(value, curr)) {
return;
}
var grid = _parent.current_grid;
grid.write(expiration, column, value);
_parent.model.set_candidate_grid(grid);
});
return new(cell, dispose);
VolGridTickCellVM create_tick_cell() {
var cell = new VolGridTickCellVM(column.unique_col_name);
cell.request_tick += is_up => {
var col = _parent.get_column(column.unique_col_name);
if (col is null) {
throw new InvalidOperationException(
$"Failed to find column with id {column.unique_col_name}");
}
if (col.model?.tick_move is var tm) {
cell.candidate_value = tm?.Invoke(cell.candidate_value, is_up);
return;
}
throw new InvalidOperationException($"tick_move is not defined");
};
return cell;
}
}
void _sync_cell(VolGridCellVM cell) {
if (cell is null) {
return;
}
cell.committed_value = _parent.committed_grid.read(_exp, cell.column_id);
cell.candidate_value = _parent.current_grid.read(_exp, cell.column_id);
}
class CellData : IDisposable {
IDisposable _dispose;
public CellData(VolGridCellVM vm, IDisposable dispose) {
this.vm = vm;
_dispose = Disposable.Create(vm, dispose);
}
public VolGridCellVM vm { get; }
public void Dispose() =>
Disposable.dispose(ref _dispose);
}
}
}
@@ -3,6 +3,8 @@ using mbts.ui;
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -21,7 +23,7 @@ namespace mbts.spark {
if (_settings.precomputed_theo_handles == null)
_settings.precomputed_theo_handles = new List<double>();
vol_surface_name = vs_name;
this.commit = new DelegateCommand(() => request_commit?.Invoke(ProtoBufSerializationHelper.clone_protobuf(_settings)));
this.commit = new DelegateCommand(() => request_commit?.Invoke(ProtobufSerializationHelper.clone(_settings)));
}
public event Action<VolSurfaceAdvancedSettings> request_commit;
@@ -9,6 +9,8 @@ namespace mbts.spark {
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
@@ -23,6 +25,9 @@ namespace mbts.spark {
readonly VolSurfaceSettings _settings;
readonly VolSurfaceCoreSettings _core_settings;
string _selected_section;
bool _can_edit_name = true;
public VolSurfaceSettingsEditorVM(IBus bus, VolSurfaceSettings settings, Action<VolSurfaceSettings> commit) {
if (settings is null) {
throw new ArgumentNullException(nameof(settings));
@@ -113,7 +118,23 @@ namespace mbts.spark {
}
}
public string vol_surface_name { get { return _core_settings.vol_surface_name; } }
public string vol_surface_name {
get => _core_settings.vol_surface_name;
set {
using var _ = detect_property_change();
_core_settings.vol_surface_name = value;
}
}
public bool can_edit_name {
get => _can_edit_name;
set => Set(ref _can_edit_name, value);
}
public string selected_section {
get => _selected_section;
set => Set(ref _selected_section, value);
}
public VSSymbolStructureVM symbol_structure_vm { get; set; }
public VolModelPolynomialVM vol_model_polynomial_vm { get; } = new();
@@ -353,7 +374,7 @@ namespace mbts.spark {
public ICommand commit { get; }
public VolSurfaceSettings get_settings() {
var rv = ProtoBufSerializationHelper.clone_protobuf(_settings);
var rv = ProtobufSerializationHelper.clone(_settings);
var symbols = symbol_structure_vm.driver_grids
.SelectMany(dg => dg.symbols.Where(sym => sym.is_selected))
.ToList();
@@ -522,11 +543,16 @@ namespace mbts.spark {
}
public class VSSymbolStructureVM : DisposableViewModelBase {
readonly Property<VSSymbolGridVM> _selected_driver_grid;
public VSSymbolStructureVM(IBus bus, VolSurfaceSettings settings) {
driver_grids = new ObservableCollection<VSSymbolGridVM>();
_selected_driver_grid = backing<VSSymbolGridVM>(nameof(selected_driver_grid));
settings.core_settings.master_slave_relationships ??= new List<VolSurfaceSymbolRelationship>();
settings.core_settings.implied_vol_marketdata_relationships ??= new List<VolSurfaceSymbolRelationship>();
_dispose = new DisposableCombo(
driver_grids.Subscribe((s, e) =>
selected_driver_grid ??= driver_grids.FirstOrDefault()),
bus.subscribe(SparkTags.ExpirationParametersInputTag).OnDispatcher().Subscribe(on_exp_params_input)) +
new Action(() => Disposable.dispose(driver_grids));
@@ -586,6 +612,10 @@ namespace mbts.spark {
public IReadOnlyList<VolSurfaceEnums.VolSurfacePricingModel> pricing_models => EnumHelper.get_values<VolSurfaceEnums.VolSurfacePricingModel>();
public ObservableCollection<VSSymbolGridVM> driver_grids { get; private set; }
public VSSymbolGridVM selected_driver_grid {
get => _selected_driver_grid.Value;
set => _selected_driver_grid.set(value);
}
}
public class RotationVM : ViewModelBase, IEquatable<RotationVM> {
@@ -1,14 +1,15 @@
namespace mbts.spark {
using bts;
using bts.utils;
using mbts.ui;
using mbts.ui.shell;
using Spark.Core.Reflection;
using Spark.ViewModel.Commands;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;
class VolSurfaceMacroActionsVM : ViewModelBase {
readonly VolSurfaceDisplayModel _model;
@@ -76,8 +77,8 @@
public IRaiseCanExecuteChangedCommand vol_shift { get; }
IEnumerable<IRaiseCanExecuteChangedCommand> _commands =>
ObjectSnapshot.property_delegates_of_type<VolSurfaceMacroActionsVM, IRaiseCanExecuteChangedCommand>()
.Select(g => g(this));
ReflectionHelper.property_getters<VolSurfaceMacroActionsVM, IRaiseCanExecuteChangedCommand>()
.Select(pg => pg.get(this));
public void selection_changed(IEnumerable<VolSurfaceDisplayGridExpiration> selected) {
_selected_exps = selected.ToList();
@@ -7,6 +7,8 @@
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.ViewModel.Commands;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+129 -96
View File
@@ -1,5 +1,5 @@
#nullable enable
namespace mbts.spark {
using bts;
using bts.api;
using bts.collections;
@@ -8,48 +8,105 @@ namespace mbts.spark {
using mbts.spark.VolSurface;
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.settings;
using mbts.ui.shell;
using Spark.ViewModel.Commands;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
class VolSurfaceVM : ViewModelBase, IDisposable {
class VolSurfaceVM : DisposableViewModelBase {
readonly int _vs_id;
readonly IBus _bus;
readonly string _request_id = Guid.NewGuid().ToString();
VolSurfaceDisplayModel _model;
VolSurfaceMacroGridSettings _grid_settings;
readonly VolSurfaceDisplayModel _model;
readonly IRaiseCanExecuteChangedCommand _revert_cmd;
readonly IRaiseCanExecuteChangedCommand _commit_cmd;
readonly IDialogCommand _main_settings_cmd;
readonly IDialogCommand _advanced_settings_cmd;
readonly IDialogCommand _grid_settings_cmd;
public VolSurfaceVM(VolSurfaceDisplayModel model, int id, IBus bus, VolSurfaceWindowSettings startup_data) {
Log.notnull(startup_data);
string? _selected_state = string.Empty;
VolSurfaceMacroGridSettings _grid_settings;
bool _ignore_implied_vol_settings;
public VolSurfaceVM(
VolSurfaceDisplayModel model, int id, IBus bus, VolSurfaceWindowSettings startup_data) {
_model = model;
var demux = new VolSurfaceEventDemux(model);
_vs_id = id;
_bus = bus;
macro_actions = new VolSurfaceMacroActionsVM(_model);
globals = new VolSurfaceGlobalParameterVM(_model);
// grid
_grid_settings = startup_data.macro_grid_settings ?? new VolSurfaceMacroGridSettings();
var hidden_exps_set = startup_data.hidden_exps.empty_if_null().ToHashSet();
grid = new VolSurfaceGridVM(
this, _model, _grid_settings.hidden_cols(), hidden_exps_set);
grid.on_selection_changed += _on_grid_selection_changed;
_model.publish_grid_settings(_grid_settings);
// graphs
var demux = new VolSurfaceEventDemux(model);
vol_curve_vm = new VolSurfaceGraphVM(
_model, demux, startup_data, (show_ivol, exp) => _model.publish_new_grid_selection(_request_id, exp, show_ivol));
_model, demux, startup_data, (show_ivol, exp) =>
_model.publish_new_grid_selection(_request_id, exp, show_ivol));
vol_terms_vm = new VolTermsGraphVM(_model, demux);
revert_command = new DelegateCommand(o => _model.revert(), o => _model.is_dirty);
commit_command = new DelegateCommand(o => _model.commit(), o => _model.is_dirty);
load_previous_command = new DelegateCommand(_ => { var cur = selected_previous_state; selected_previous_state = null; _model.load_previous_state(cur); }, _ => !string.IsNullOrEmpty(selected_previous_state));
main_settings_command = new DialogCommand(() => {
// command
_revert_cmd = new Command(o => _model.revert(), o => _model.is_dirty);
_commit_cmd = new Command(o => _model.commit(), o => _model.is_dirty);
load_previous_cmd = new Command(
load_previous, () => !selected_previous_state.is_null_or_empty());
_main_settings_cmd = new DialogCommand(mk_main_settings_win);
_advanced_settings_cmd = new DialogCommand(mk_advanced_settings_win);
_grid_settings_cmd = new DialogCommand(mk_grid_settings_win);
_model.on_dirty_change += () => {
RaisePropertyChanged(nameof(is_dirty));
_revert_cmd.RaiseCanExecuteChanged();
_commit_cmd.RaiseCanExecuteChanged();
};
demux.on_candidate_grid_change += () =>
previous_states.sync_with(_model.get_previous_states());
demux.on_schema_change += () => {
var existing_cols = _grid_settings.column_settings.ToDictionary(c => c.id);
_grid_settings.set_columns(
model.get_active_grid()
.get_ordered_columns()
.Select(col => existing_cols.GetValueOrDefault(col.unique_col_name) ??
VolSurfaceColumnSettings.from_column_model(col)));
};
_dispose = Disposable.Create(
vol_curve_vm,
vol_terms_vm,
globals,
Disposable.Create(() => grid?.Dispose()),
_main_settings_cmd,
_advanced_settings_cmd,
_grid_settings_cmd,
_model);
Window? mk_main_settings_win() {
var settings = _model.get_active_settings();
if (settings == null) {
if (settings is null) {
return null;
}
return new VolSurfaceSettingsEditor { DataContext = new VolSurfaceSettingsEditorVM(_bus, settings, _model.set_candidate_settings) };
});
advanced_settings_command = new DialogCommand(() => {
return new VolSurfaceSettingsEditor {
DataContext = new VolSurfaceSettingsEditorVM(
_bus, settings, _model.set_candidate_settings) {
can_edit_name = false
}
};
}
Window? mk_advanced_settings_win() {
var settings = _model.get_active_settings();
if (settings == null) {
return null;
@@ -69,76 +126,71 @@ namespace mbts.spark {
// )
// };
return null;
});
grid_settings_command = new DialogCommand(() => {
}
Window? mk_grid_settings_win() {
var settings = _model.get_active_settings();
if (settings == null) {
if (settings is null) {
return null;
}
var vm = new VolSurfaceGridSettingsEditorVM(settings.core_settings.vol_surface_name, _grid_settings.Clone());
var vm = new VolSurfaceGridSettingsEditorVM(
settings.core_settings.vol_surface_name, _grid_settings.Clone());
vm.request_commit += on_grid_settings;
return new VolSurfaceGridSettingsEditor {
DataContext = vm
};
});
_model.on_dirty_change += raise_dirty_changed;
macro_actions = new VolSurfaceMacroActionsVM(_model);
globals = new VolSurfaceGlobalParameterVM(_model);
demux.on_candidate_grid_change += () => previous_states.sync_with(_model.get_previous_states());
demux.on_schema_change += () => {
// _grid_settings.clear_columns();
var existing_cols = _grid_settings.column_settings.ToDictionary(c => c.id);
_grid_settings.set_columns(
model.get_active_grid()
.get_ordered_columns()
.Select(col => {
if (!existing_cols.TryGetValue(col.unique_col_name, out var rv)) {
rv = VolSurfaceColumnSettings.from_column_model(col);
}
return rv;
}));
};
grid = new VolSurfaceGridVM(this, _model, _grid_settings.hidden_cols(), new HashSet<VolSurfaceExpiration>(startup_data.hidden_exps ?? Enumerable.Empty<VolSurfaceExpiration>()));
grid.on_selection_changed += _on_grid_selection_changed;
void on_grid_settings(VolSurfaceMacroGridSettings new_settings) {
using var _ = grid.defer_invalidate_rows();
_grid_settings = new_settings;
grid.load_from(_grid_settings);
grid.invalidate_rows();
_model.publish_grid_settings(_grid_settings);
void on_grid_settings(VolSurfaceMacroGridSettings new_settings) {
using var _ = grid.defer_invalidate_rows();
_grid_settings = new_settings;
grid.load_from(_grid_settings);
grid.invalidate_rows();
_model.publish_grid_settings(_grid_settings);
}
}
void load_previous() {
var cur = selected_previous_state;
selected_previous_state = null;
_model.load_previous_state(cur);
}
}
public VolSurfaceGridVM grid { get; private set; }
public VolSurfaceGraphVM vol_curve_vm { get; private set; }
public VolTermsGraphVM vol_terms_vm { get; private set; }
public VolSurfaceMacroActionsVM macro_actions { get; private set; }
public VolSurfaceGlobalParameterVM globals { get; private set; }
public VolSurfaceGridVM grid { get; }
public VolSurfaceGraphVM vol_curve_vm { get; }
public VolTermsGraphVM vol_terms_vm { get; }
public VolSurfaceMacroActionsVM macro_actions { get; }
public VolSurfaceGlobalParameterVM globals { get; }
private bool _ignore_implied_vol_settings;
public bool ignore_implied_vol_settings { get { return _ignore_implied_vol_settings; } set { _model.publish_ignore_implied_vol_settings(_request_id, _ignore_implied_vol_settings = value); } }
public bool is_dirty { get { return _model.is_dirty; } }
public IRaiseCanExecuteChangedCommand revert_command { get; private set; }
public IRaiseCanExecuteChangedCommand commit_command { get; private set; }
public IDialogCommand main_settings_command { get; private set; }
public IDialogCommand advanced_settings_command { get; private set; }
public IDialogCommand grid_settings_command { get; private set; }
public ICommand details_command => new DelegateCommand(_ => _show_details());
public ICommand load_previous_command { get; private set; }
public ObservableCollection<string> previous_states { get; } = new();
private string _selected_state = string.Empty;
public string selected_previous_state {
get { return _selected_state; }
public bool ignore_implied_vol_settings {
get => _ignore_implied_vol_settings;
set {
_selected_state = value;
load_previous_command.TryRaiseCanExecuteChanged();
RaisePropertyChanged();
if (Set(ref _ignore_implied_vol_settings, value)) {
_model.publish_ignore_implied_vol_settings(_request_id, value);
}
}
}
public ObservableCollection<string> previous_states { get; } = new();
public string? selected_previous_state {
get => _selected_state;
set {
if (Set(ref _selected_state, value)) {
load_previous_cmd.TryRaiseCanExecuteChanged();
}
}
}
public bool is_dirty => _model.is_dirty;
public ICommand revert_cmd => _revert_cmd;
public ICommand commit_cmd => _commit_cmd;
public ICommand main_settings_cmd => _main_settings_cmd;
public ICommand advanced_settings_cmd => _advanced_settings_cmd;
public ICommand grid_settings_cmd => _grid_settings_cmd;
public ICommand details_command => new Command(_show_details);
public ICommand load_previous_cmd { get; }
public VolSurfaceWindowSettings get_startup_data() {
var rv = new VolSurfaceWindowSettings {
id = _vs_id,
@@ -152,39 +204,20 @@ namespace mbts.spark {
return rv;
}
public void Dispose() {
vol_curve_vm.Dispose();
vol_terms_vm.Dispose();
globals.Dispose();
if (grid != null) grid.Dispose();
main_settings_command.Dispose();
advanced_settings_command.Dispose();
grid_settings_command.Dispose();
Disposable.dispose(ref _model);
}
void raise_dirty_changed() {
RaisePropertyChanged("is_dirty");
revert_command.RaiseCanExecuteChanged();
commit_command.RaiseCanExecuteChanged();
}
void _on_grid_selection_changed(IEnumerable<VolSurfaceDisplayGridExpiration> selection) {
var selected = selection.FirstOrDefault();
if (selected != null) {
if (selection.TryGetFirst(out var selected)) {
vol_curve_vm.set_visible_expiration(selected);
_model.publish_new_grid_selection(_request_id, selected, vol_curve_vm.show_implied_vol);
}
macro_actions.selection_changed(selection);
}
async Task<VolSurfaceSettings> _get_volsurface_settings() =>
(await _bus.subscribe(SparkTags.VolSurfaceCommittedOutputTag(_vs_id)).FirstOrDefaultAsync())
?.volsurface_input
?.surface_settings;
void _show_details() =>
_model.show_details();
async Task<VolSurfaceSettings?> _get_volsurface_settings() =>
(await _bus.subscribe(SparkTags.VolSurfaceCommittedOutputTag(_vs_id)).FirstOrDefaultAsync())
?.volsurface_input
?.surface_settings;
}
}
@@ -1,19 +1,21 @@
using bts.api;
using bts.utils;
namespace mbts.spark {
using bts.api;
using bts.collections;
using mbts.analytics;
using mbts.collections;
using mbts.ui;
using mbts.ui.shell;
using mbts.analytics;
using mbts.collections;
using mbts.ui;
using mbts.ui.shell;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Windows.Media;
using Spark.Core;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Windows.Media;
namespace mbts.spark {
class VolTermsGraphVM : DisposableViewModelBase {
readonly VolSurfaceDisplayModel _model;
readonly DateTimeAxisVM _exp_terms_x_axis;
@@ -5,6 +5,8 @@
using mbts.analytics;
using mbts.ui.controls;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -296,7 +298,7 @@
bool succ = false;
VolSurfaceInputSnapshot vs_sn = _input_snapshot_list.ToList().Find(v => v.save_marker == state_name);
if (vs_sn != null) {
VolSurfaceInput vs_inp = VolSurfaceUtilityFunctions.deserialize_proto<VolSurfaceInput>(vs_sn.data);
var vs_inp = ProtobufSerializationHelper.deserialize<VolSurfaceInput>(vs_sn.data);
if (vs_inp != null) {
_change_state(DisplayModelState.WaitingForCalcResponse);
_bus.post(SparkTags.VolSurfaceCalculationRequestTag(_vs_id),
@@ -319,7 +321,7 @@
public byte[] get_current_state() {
DisplayModelData curr_data = _get_current_data();
if (curr_data != null && curr_data.vs_output != null && curr_data.vs_output.volsurface_input != null)
return VolSurfaceUtilityFunctions.serialize_proto(curr_data.vs_output.volsurface_input);
return ProtobufSerializationHelper.serialize(curr_data.vs_output.volsurface_input);
else
return null;
}
@@ -327,7 +329,7 @@
/// Sets the state that is passed in bytes form. Returns
/// true is state is set successfully
public bool set_state(byte[] file_data) {
VolSurfaceInput vs_input = VolSurfaceUtilityFunctions.deserialize_proto<VolSurfaceInput>(file_data);
var vs_input = ProtobufSerializationHelper.deserialize<VolSurfaceInput>(file_data);
if (vs_input != null) {
if (_state == DisplayModelState.Idle || _state == DisplayModelState.ResponseReady) {
_change_state(DisplayModelState.WaitingForCalcResponse);
+94 -3
View File
@@ -1,4 +1,4 @@
namespace mbts.spark {
namespace mbts.spark {
using bts.api;
using bts.api.analytics;
using bts.utils;
@@ -34,6 +34,9 @@
public static HashSet<string> hidden_cols(this VolSurfaceMacroGridSettings gs) =>
new(gs.column_settings.Where(cc => !cc.is_visible).Select(cc => cc.id));
public static bool is_editable(this VolSurfaceColumnType vs_col_type) =>
vs_col_type is VolSurfaceColumnType.ReadWriteTick;
public static analytics.VolSurfaceExpiration ToVSExp(this VolSurfaceDisplayGridExpiration vsdge) =>
new() { expiration = vsdge.expiration, symbol = vsdge.symbol };
@@ -80,10 +83,10 @@
_ => false,
};
public static IEnumerable<VolSurfaceExpiration> select_exp(this IEnumerable<VolSurfaceRowContext> rows) =>
public static IEnumerable<VolSurfaceExpiration> select_exp(this IEnumerable<VolSurfaceRowVM> rows) =>
rows.Select(r => r.expiration.ToVSExp());
public static IEnumerable<VolSurfaceDisplayGridExpiration> select_display_exp(this IEnumerable<VolSurfaceRowContext> rows) =>
public static IEnumerable<VolSurfaceDisplayGridExpiration> select_display_exp(this IEnumerable<VolSurfaceRowVM> rows) =>
rows.Select(r => r.expiration);
public static IEnumerable<VolSurfaceDisplayGridExpiration> where_master(this IEnumerable<VolSurfaceDisplayGridExpiration> rows) =>
@@ -113,6 +116,94 @@
public static IEnumerable<(double x, double y)> real_all_points(this VolCurveDisplayGraph graph) =>
_select_real_points(graph.all_points);
public static bool is_delta_greek(this VolSurfaceGreeks g) =>
g switch {
VolSurfaceGreeks.Delta or
VolSurfaceGreeks.Bsmdelta or
VolSurfaceGreeks.FlatVolDelta or
VolSurfaceGreeks.ExpirationDelta or
VolSurfaceGreeks.Charm or
VolSurfaceGreeks.Vanna => true,
_ => false,
};
public static bool is_gamma_greek(this VolSurfaceGreeks g) =>
g switch {
VolSurfaceGreeks.Gamma or
VolSurfaceGreeks.Bsmgamma => true,
_ => false
};
public static bool is_oev_col(this VolSurfaceGreeks g) =>
g switch {
VolSurfaceGreeks.Oev or
VolSurfaceGreeks.Bsmoev => true,
_ => false
};
public static VolSurfaceExpiration to_vs_exp(this SecurityExpiration sec_exp) =>
new() { security_type = sec_exp.security_type, symbol = sec_exp.symbol, expiration = sec_exp.expiration };
public static DriverCalculationType to_driver_calc_type(
this ExpirationDriver.ModeOneofCase driver_mode) =>
driver_mode switch {
ExpirationDriver.ModeOneofCase.Security => DriverCalculationType.Direct,
ExpirationDriver.ModeOneofCase.TimeWeightedInterpolated => DriverCalculationType.TimeWeightedInterp,
_ => throw new NotImplementedException()
};
public static SecurityExpiration to_sec_exp(
this bts.api.domain.SecurityExpiration api_sec_exp) =>
to_sec_exp(new bts.api.domain.SecurityExpirationImmutable(api_sec_exp));
public static SecurityExpiration to_sec_exp(
this bts.api.domain.SecurityExpirationImmutable api_sec_exp) =>
new(
api_sec_exp.Exchange.to_venue(),
api_sec_exp.SecurityType.contract_case(),
api_sec_exp.Symbol,
api_sec_exp.Expiration.date_time());
public static SecurityExpiration to_sec_exp(this Security sec) =>
to_sec_exp(new SecurityImmutable(sec));
public static SecurityExpiration to_sec_exp(this SecurityImmutable sec) {
var exp_date = sec.security_expiration() ?? throw new InvalidOperationException();
return new(sec.Exchange, sec.ContractCase, sec.Symbol, exp_date, sec.Id);
}
public static ExpirationDriver to_exp_driver(this SecurityExpiration sec_exp) =>
new() {
Security = new() {
Symbol = sec_exp.symbol,
Expiration = new() {
ExpirationDay = (uint)sec_exp.expiration.Day,
ExpirationMonth = (uint)sec_exp.expiration.Month,
ExpirationYear = (uint)sec_exp.expiration.Year,
},
Exchange = sec_exp.exchange.to_api_venue(),
}
};
public static ExpirationDriverImmutable to_exp_driveri(this SecurityExpiration sec_exp) =>
new(to_exp_driver(sec_exp));
public static bts.api.domain.SecurityExpiration to_api_sec_exp(this SecurityExpiration sec_exp) =>
new() {
Exchange = sec_exp.exchange.to_api_venue(),
SecurityType = sec_exp.security_type,
Symbol = sec_exp.symbol,
Expiration = new() {
ExpirationDay = (uint)sec_exp.expiration.Day,
ExpirationMonth = (uint)sec_exp.expiration.Month,
ExpirationYear = (uint)sec_exp.expiration.Year
}
};
public static bts.api.domain.SecurityExpirationImmutable to_api_sec_expi(
this SecurityExpiration sec_exp) =>
new(to_api_sec_exp(sec_exp));
static IEnumerable<(double x, double y)> _select_real_points(IEnumerable<Tuple<double, double>> points) =>
points.Where(pt => pt.Item1.is_real() && pt.Item2.is_real()).Select(t => (t.Item1, t.Item2));
}
+6 -5
View File
@@ -24,13 +24,14 @@ Value: OptionDriverPriceMap which is a wrapper around
IDictionary<SecurityExpiration, Tuple<Security, VolSurfaceBBOUnit>>
----------------------------------------------------------------
SingleVolSurfaceInterpGreeksPublisher listens to all inputs and publishes
exp vs InterpGreeks
SingleVolSurfaceInterpGreeksPublisher (for one vs) listens to all inputs and publishes
IDictionary<VolSurfaceExpiration, IEnumerable<Theos>>
VolSurfaceInterpGreeksMultiplexer listens to all vol surfaces, resolves symbols and
publishes symbol vs InterpGreeks
VolSurfaceInterpGreeksMultiplexer (for multiple option symbols) listens to all vol
surfaces, resolves symbols and for each option_symbol publishes
OptionTheoInterpolationData*
SymbolAggregationPublisher is a thin class that combines individual symbol data and
SymbolAggregationPublisher is a thin generic class that combines individual symbol data and
publishes symbol vs data map
LiveTheoPublisher:
+10 -4
View File
@@ -1,6 +1,8 @@
using bts;
using bts.api;
using bts.api.admin;
using bts.api.core;
using bts.collections;
using bts.utils;
using System;
@@ -18,10 +20,10 @@ namespace mbts.spark {
IReadOnlyDictionary<uint, string> _account_map = DictionaryHelper.empty<uint, string>();
[ImportingConstructor]
public AdminModel(AdminService service, Lazy<UserTuple> user)
: this(service, user.Value) { }
public AdminModel(IBus bus, AdminService service, Lazy<UserTuple> user)
: this(bus, service, user.Value) { }
AdminModel(AdminService service, UserTuple user) {
AdminModel(IBus bus, AdminService service, UserTuple user) {
this.user = user;
// accounts
on_accounts = service.subscribei_admin_data()
@@ -48,7 +50,11 @@ namespace mbts.spark {
.Table(UserTuple.key_fn)
.Cache() :
Observable.Return(TableUpdate<UserTuple, uint>.mk_empty(UserTuple.key_fn).with_added(new[] { user }));
_dispose = on_accounts.Subscribe(map => _account_map = map);
_dispose = on_accounts.Subscribe(map => {
_account_map = map;
var account_tuple_map = MappedDictionary.create(map, (id, name) => new AccountTuple(id, name));
bus.post(SparkTags.AccountsTag, account_tuple_map);
});
}
public IObservable<IReadOnlyDictionary<uint, string>> on_users { get; }
+2 -2
View File
@@ -82,7 +82,7 @@ namespace mbts.spark {
this AlgoTypeSetImmutable algo_set,
DynamicOrderHelper dynamic_helper,
Func<CustomOrderDefinitionImmutable, CustomOrderDefinitionImmutable> fit_to_type = null,
uint display_qty_divisor = 1) =>
double display_qty_divisor = 1) =>
//
algo_set.factory_types
.Select(algo_type => {
@@ -109,7 +109,7 @@ namespace mbts.spark {
SecurityCriteriaClause clause,
DynamicOrderHelper dynamic_helper,
Func<CustomOrderDefinitionImmutable, CustomOrderDefinitionImmutable> fit_to_type = null,
uint display_qty_divisor = 1) {
double display_qty_divisor = 1) {
//
ImmutableDictionary<AlgoKey, AlgoData> rv = null;
foreach (var set in security_algo_sets) {
+27 -21
View File
@@ -1,4 +1,5 @@
using bts.api;
using bts;
using bts.api;
using bts.api.core;
using bts.api.orderman;
using bts.utils;
@@ -50,9 +51,7 @@ namespace mbts.spark {
/// <see cref="subscribe_algos"/>,
/// <see cref="subscribe_algos(SecurityCriteriaClause)"/>,
/// <see cref="subscribe_algos(SecurityImmutable)"/>
_studio_algos_source = studio_model.definitions
.StartWith(TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn))
.Cache();
_studio_algos_source = studio_model.definitions.Cache();
}
public AlgoTypeSetImmutable get_permitted_algos(SecurityImmutable security) =>
@@ -67,10 +66,11 @@ namespace mbts.spark {
public IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos() =>
_studio_algos_source
.AppendTable(_security_algo_types
.Select(s => s.algo_type_set)
.Aggregate(AlgoTypeSetImmutable.empty, (a, b) => a.union_with(b))
.define_algos(_dynamic_helper));
.StartWith(TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn))
.AppendTable(_security_algo_types
.Select(s => s.algo_type_set)
.Aggregate(AlgoTypeSetImmutable.empty, (a, b) => a.union_with(b))
.define_algos(_dynamic_helper));
public IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos(SecurityCriteriaClause security_clause) {
var system_algos = _security_algo_types.match_algos(
@@ -78,11 +78,13 @@ namespace mbts.spark {
_dynamic_helper,
def => _fit_to_type(def, security_clause, _security_algo_types));
return _studio_algos_source.Select(
a => (algo: a, fitted_def: _fit_to_type(a.value, security_clause, _security_algo_types)),
tup => tup.algo.key)
.Select(tup => AlgoData.create(tup.fitted_def, tup.algo.name, tup.algo.key), a => a.key)
.AppendTable(system_algos.Values);
return _studio_algos_source
.Select(
a => (algo: a, fitted_def: _fit_to_type(a.value, security_clause, _security_algo_types)),
tup => tup.algo.key)
.Select(tup => AlgoData.create(tup.fitted_def, tup.algo.name, tup.algo.key), a => a.key)
.StartWith(TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn))
.AppendTable(system_algos.Values);
}
public IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos(SecurityImmutable security) {
@@ -96,14 +98,18 @@ namespace mbts.spark {
def => _fit_to_type(def, security, _security_algo_types),
_security_auxiliary_model.get_display_quantity_divisor(security));
return _studio_algos_source.Select(
a => (algo: a, fitted_def: _fit_to_type(a.value, security, _security_algo_types)),
tup => tup.algo.key)
// filter out algos that use an unsupported root, because this would have the effect of duplicating the default algo
// (e.g., GlbxIceberg orders would be converted to Limit/Spreader orders for non-Glbx securities).
.Filter(tup => tup.fitted_def.actual().CustomCase == tup.algo.value.actual().CustomCase, tup => tup.algo.key)
.Select(tup => AlgoData.create(tup.fitted_def, tup.algo.name, tup.algo.key), AlgoData.key_fn)
.AppendTable(system_algos.Values);
var filtered_studio_algos = _studio_algos_source
.StartWith(TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn))
.Select(
a => (algo: a, fitted_def: _fit_to_type(a.value, security, _security_algo_types)),
tup => tup.algo.key)
// filter out algos that use an unsupported root, because this would have the effect of duplicating the default algo
// (e.g., GlbxIceberg orders would be converted to Limit/Spreader orders for non-Glbx securities).
.Filter(tup => tup.fitted_def.actual().CustomCase == tup.algo.value.actual().CustomCase, tup => tup.algo.key)
.Select(tup => AlgoData.create(tup.fitted_def, tup.algo.name, tup.algo.key), AlgoData.key_fn);
return filtered_studio_algos
.StartWith(TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn))
.AppendTable(system_algos.Values);
}
protected virtual void assign_fallback_algo(CustomOrderDefinition mdef, SecurityCriteriaClause security_clause) {
@@ -1,7 +1,7 @@
namespace mbts.analytics {
using bts;
using mbts.ui.shell;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
@@ -40,7 +40,7 @@
new Dictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData>());
public VolSurfaceOutput Clone() => new(
ProtoBufSerializationHelper.clone_protobuf(volsurface_input),
ProtobufSerializationHelper.clone(volsurface_input),
new Dictionary<VolSurfaceExpiration, VolCurveOutput>(exp_output_map),
new Dictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData>(aux_data_map));
@@ -1,112 +1,194 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ProtoBuf;
using bts.api;
using bts.settings;
using bts.spark;
using mbts.spark;
#nullable enable
namespace mbts {
[ProtoBuf.ProtoContract()]
using bts.api;
using bts.utils;
using mbts.ui.utility;
using mbts.utils;
using ProtoBuf;
using Spark.Core.Collections;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
[ProtoContract]
[Serializable]
public class SecurityExpiration : IEquatable<SecurityExpiration> {
[ProtoBuf.ProtoMember(1)]
private readonly SecurityTuple _sec_tup;
[ProtoBuf.ProtoMember(2)]
public readonly DateTime expiration;
[ProtoBuf.ProtoMember(2)]
private readonly Nullable<uint> _id;
public readonly static SecurityExpiration empty = new SecurityExpiration(SecurityTuple.empty.security_exchange, SecurityTuple.empty.security_type, SecurityTuple.empty.security_name, DateTime.MinValue);
public class SecurityExpiration : IProtobuf<SecurityExpiration> {
public readonly static SecurityExpiration empty = new(
SecurityTuple.empty.security_exchange,
SecurityTuple.empty.security_type,
SecurityTuple.empty.security_name,
DateTime.MinValue);
// for ProtoBuf deserialization
private SecurityExpiration() { }
// for deserialization
SecurityExpiration() =>
security_tuple = SecurityTuple.empty;
public SecurityExpiration(Venue exchange, Security.ContractOneofCase type, string symbol, DateTime exp, Nullable<uint> id = null)
public SecurityExpiration(
Venue exchange,
Security.ContractOneofCase type,
string symbol,
DateTime exp,
uint? id = null)
: this(exchange, type.security_type(), symbol, exp, id) { }
public SecurityExpiration(Venue exchange, SecurityType type, string symbol, DateTime exp, Nullable<uint> id = null)
: this(new SecurityTuple(type, symbol, exchange), exp, id) { }
public SecurityExpiration(
Venue exchange, SecurityType type, string symbol, DateTime expiration, uint? id = null)
: this(new SecurityTuple(type, symbol, exchange), expiration, id) { }
public SecurityExpiration(SecurityTuple sec_tup, DateTime exp, Nullable<uint> id = null) {
_sec_tup = sec_tup;
expiration = exp;
_id = id;
public SecurityExpiration(
SecurityTuple security_tuple, DateTime expiration, uint? id = null) {
this.security_tuple = security_tuple;
this.expiration = expiration;
this.id = id;
}
public SecurityTuple security_tuple { get { return _sec_tup; } }
[ProtoMember(1)]
public SecurityTuple security_tuple { get; }
public SecurityType security_type { get { return _sec_tup.security_type; } }
[ProtoMember(2)]
public DateTime expiration { get; }
public string symbol { get { return _sec_tup.security_name; } }
[ProtoMember(3)]
public uint? id { get; }
public Venue exchange { get { return _sec_tup.security_exchange; } }
public SecurityType security_type => security_tuple?.security_type ?? SecurityType.Unset;
public string symbol => security_tuple?.security_name ?? string.Empty;
public Venue exchange => security_tuple?.security_exchange ?? Venue.Unset;
public bool is_empty() { return Equals(empty); }
public Nullable<uint> id() { return _id; }
public SecurityExpiration unset_exchange() {
return new SecurityExpiration(Venue.Unset, security_type, symbol, expiration);
[Flags]
public enum Properties {
Type = 1,
Symbol = 1 << 1,
Expiration = 1 << 2,
Venue = 1 << 3,
Id = 1 << 4
}
public bool Equals(SecurityExpiration other) {
if (other != null)
return _sec_tup.Equals(other._sec_tup) && expiration.Equals(other.expiration);
else
return false;
public static IEqualityComparer<SecurityExpiration> get_eq_comparer() =>
get_eq_comparer(
Properties.Type, Properties.Symbol, Properties.Expiration, Properties.Venue);
public static IEqualityComparer<SecurityExpiration> get_eq_comparer(Properties props) {
return EqualityComparerBuilder.create_comparer(
EnumHelper.split_flags(props).Select(get_prop_comparer));
static IEqualityComparer<SecurityExpiration> get_prop_comparer(Properties single_prop) =>
single_prop switch {
Properties.Type => wrap(s => s.security_type),
Properties.Symbol => wrap(s => s.symbol).to_safe(),
Properties.Expiration => wrap(s => s.expiration),
Properties.Venue => wrap(s => s.exchange),
Properties.Id => wrap(s => s.id).to_safe(),
_ => throw new NotImplementedException()
};
static IEqualityComparer<SecurityExpiration> wrap<T>(
Func<SecurityExpiration, T> selector, IEqualityComparer<T>? comparer = null) =>
EqualityComparer.Create(selector, comparer ?? EqualityComparer<T>.Default);
}
#region Object overrides
public static IEqualityComparer<SecurityExpiration> get_eq_comparer(params Properties[] hierarchy) =>
EqualityComparerBuilder.create(hierarchy.Select(get_eq_comparer)).to_comparer();
public override int GetHashCode() { return _sec_tup.GetHashCode() ^ expiration.GetHashCode(); }
public static IComparer<SecurityExpiration> get_comparer() =>
get_comparer(Properties.Venue, Properties.Type, Properties.Symbol, Properties.Expiration);
public override bool Equals(object obj) {
return Equals(obj as SecurityExpiration);
public static IComparer<SecurityExpiration> get_comparer(Properties prop) {
return prop switch {
Properties.Type => wrap(s => s.security_type),
Properties.Symbol => wrap(s => s.symbol),
Properties.Expiration => wrap(s => s.expiration),
Properties.Venue => wrap(s => s.exchange),
Properties.Id => wrap(s => s.id).to_safe(),
_ => throw new NotImplementedException()
};
static IComparer<SecurityExpiration> wrap<T>(
Func<SecurityExpiration, T> selector, IComparer<T>? comparer = null) =>
(comparer ?? Comparer<T>.Default).wrap(selector);
}
public static bool operator ==(SecurityExpiration x, SecurityExpiration y) {
if (Object.ReferenceEquals(x, null)) return Object.ReferenceEquals(y, null);
if (Object.ReferenceEquals(y, null)) return false;
return x.Equals(y);
}
public static bool operator !=(SecurityExpiration x, SecurityExpiration y) { return !(x == y); }
public static IComparer<SecurityExpiration> get_comparer(params Properties[] hierarchy) =>
ComparerBuilder.create(hierarchy.Select(get_comparer)).to_comparer();
public override string ToString() {
return String.Format("{0} {1}", _sec_tup.ToString(), expiration.ToShortDateString());
}
#endregion
public static IComparer<SecurityExpiration> get_exp_based_comparer() =>
get_comparer(Properties.Expiration, Properties.Venue, Properties.Type, Properties.Symbol);
public static int ExpBasedCompare(SecurityExpiration x, SecurityExpiration y) {
if (y == null) return 1;
if (x == null) return -1;
int rv = x.expiration.CompareTo(y.expiration);
if (rv == 0)
rv = x._sec_tup.CompareTo(y._sec_tup);
return rv;
}
public bool is_empty() => Equals(empty);
public static int SecBasedCompare(SecurityExpiration x, SecurityExpiration y) {
if (y == null) return 1;
if (x == null) return -1;
int rv = x._sec_tup.CompareTo(y._sec_tup);
if (rv == 0)
rv = x.expiration.CompareTo(y.expiration);
return rv;
public SecurityExpiration unset_exchange() =>
new(Venue.Unset, security_type, symbol, expiration);
public SecurityExpiration Clone() =>
new(security_tuple.Clone(), expiration, id);
public bool Equals(SecurityExpiration? other) =>
other is not null &&
security_tuple.safe_equals(other.security_tuple) &&
expiration == other.expiration;
public override bool Equals(object? obj) =>
Equals(obj as SecurityExpiration);
public override int GetHashCode() =>
HashCode.Combine(security_tuple, expiration);
object ICloneable.Clone() =>
Clone();
public static bool operator ==(SecurityExpiration? x, SecurityExpiration? y) =>
x is null ? y is null : x.Equals(y);
public static bool operator !=(SecurityExpiration x, SecurityExpiration y) =>
!(x == y);
public override string ToString() =>
$"{security_tuple} {expiration.ToShortDateString()}";
}
[ProtoContract]
public class SecurityExpirationProto : IProtobuf<SecurityExpirationProto> {
[ProtoMember(1)]
public SecurityTuple? security { get; set; }
[ProtoMember(2)]
public double expiration_oa_date { get; set; }
public SecurityExpirationProto Clone() =>
new() { security = security, expiration_oa_date = expiration_oa_date};
public bool Equals(SecurityExpirationProto? other) =>
other is not null &&
security.safe_equals(other.security) &&
expiration_oa_date.Equals(other.expiration_oa_date);
public override bool Equals(object? obj) =>
Equals(obj as SecurityExpirationProto);
public override int GetHashCode() =>
HashCode.Combine(security, expiration_oa_date);
object ICloneable.Clone() {
throw new NotImplementedException();
}
}
[ProtoBuf.ProtoContract]
public class SecurityExpirationProto {
[ProtoBuf.ProtoMember(1)]
public SecurityTuple security;
[ProtoBuf.ProtoMember(2)]
public double expiration_oa_date;
public static class SecurityExpirationExtensions {
public static SecurityExpiration with(
this SecurityExpiration sec_exp,
Venue? exchange = null,
SecurityType? security_type = null,
string? symbol = null,
DateTime? expiration = null,
Optional<uint> id = default) => new(
exchange ?? sec_exp.exchange, security_type ?? sec_exp.security_type,
symbol ?? sec_exp.symbol,
expiration ?? sec_exp.expiration,
id.has_value ? id.value : sec_exp.id);
}
}
@@ -1,58 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ProtoBuf;
using bts.api;
using bts.settings;
using bts.spark;
using mbts.spark;
#nullable enable
namespace mbts {
using bts.api;
using Spark.Core.Data;
using System;
public class SecurityStrike : IEquatable<SecurityStrike> {
public readonly SecurityExpiration expiration;
public readonly double strike;
public readonly Tuple<UInt32?, UInt32?> call_put_id;
public SecurityStrike(SecurityExpiration expiration, double strike,
Tuple<UInt32?, UInt32?> call_put_id = null) {
public SecurityStrike(
SecurityExpiration expiration, double strike, CallPutTuple<uint?> call_put_id = default) {
this.expiration = expiration;
this.strike = strike;
this.call_put_id = call_put_id;
}
public SecurityStrike(string symbol, DateTime exp, double strike,
Tuple<UInt32?, UInt32?> call_put_id = null)
: this(new SecurityExpiration(
Venue.Unset, SecurityType.Option, symbol, exp), strike, call_put_id) { }
public SecurityStrike(
string symbol, DateTime exp, double strike, CallPutTuple<uint?> call_put_id = default)
: this(new(Venue.Unset, SecurityType.Option, symbol, exp), strike, call_put_id) { }
public bool Equals(SecurityStrike other) {
if (other != null)
return expiration.Equals(other.expiration) && strike.Equals(other.strike);
else
return false;
}
public SecurityExpiration expiration { get; }
public double strike { get; }
public CallPutTuple<uint?> call_put_id { get; }
public override int GetHashCode() { return expiration.GetHashCode() ^ strike.GetHashCode(); }
/// TODO: figure out why <see cref="call_put_id"/> is excluded from equality logic
/// (was it an accident, or intentional? if the latter, why?)
public bool Equals(SecurityStrike? other) =>
other is not null &&
expiration.Equals(other.expiration) &&
strike.Equals(other.strike);
public override bool Equals(object obj) {
return Equals(obj as SecurityStrike);
}
public override int GetHashCode() =>
HashCode.Combine(expiration, strike);
public static bool operator ==(SecurityStrike x, SecurityStrike y) {
if ((object)x == null) return (object)y == null;
return x.Equals(y);
}
public override bool Equals(object? obj) =>
Equals(obj as SecurityStrike);
public static bool operator !=(SecurityStrike x, SecurityStrike y) { return !(x == y); }
public static bool operator ==(SecurityStrike x, SecurityStrike y) =>
x is null ? y is null : x.Equals(y);
public override string ToString() {
return String.Format("{0} {1}", expiration.ToString(), strike.ToString());
}
public static bool operator !=(SecurityStrike x, SecurityStrike y) =>
!(x == y);
public SecurityStrike unset_exchange() { return new SecurityStrike(expiration.unset_exchange(), strike); }
public override string ToString() =>
$"{expiration} {strike}";
public SecurityStrike unset_exchange() =>
new(expiration.with(exchange: Venue.Unset), strike);
}
}
}
@@ -5,6 +5,29 @@ namespace mbts.analytics {
/// they all in a way "derive" from core
[ProtoContract]
public class VolSurfaceSettings {
public static VolSurfaceSettings Default(string name) => new() {
core_settings = new VolSurfaceCoreSettings {
vol_surface_name = name,
vol_surface_model = VolSurfaceEnums.VolSurfaceModel.Polynomial,
call_rotation = new() { strike_vol_movement_pairs = new() },
put_rotation = new() { strike_vol_movement_pairs = new() },
strangle = new() { strike_vol_movement_pairs = new() },
full_rotation = new() { strike_vol_movement_pairs = new() },
atm_shift = new() { strike_vol_movement_pairs = new() },
symbols = new(),
symbol_structure_list = new(),
wing_settings = new() {
explicit_slope_wing_settings = new(),
implicit_slope_wing_settings = new(),
onepoint_slope_wing_settings = new()
},
unset_expiration_calculation_settings = new(),
volpath_settings = new(),
safety_limits = new(),
},
polynomial_model_settings = new()
};
[ProtoMember(10)]
public VolSurfaceCoreSettings core_settings;
[ProtoMember(15)]
@@ -1,19 +1,19 @@
using System;
using bts.api;
using bts.settings;
using bts.spark;
using bts.utils;
using mbts.spark;
using mbts.ui.converters;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ProtoBuf;
using bts.api;
using bts.settings;
using bts.spark;
using mbts.spark;
using mbts.ui.converters;
using bts.utils;
namespace mbts.analytics {
/// <summary>
/// An expiration in the Vol Surface is expressed
@@ -26,7 +26,13 @@ namespace mbts.analytics {
public class VolSurfaceExpiration : IEquatable<VolSurfaceExpiration>, IComparable<VolSurfaceExpiration> {
public VolSurfaceExpiration() : this(string.Empty, default(DateTime)) { }
public VolSurfaceExpiration(string symbol, DateTime expiration) {
public VolSurfaceExpiration(string symbol, DateTime expiration)
:
this(bts.api.SecurityType.Option, symbol, expiration) {
}
public VolSurfaceExpiration(bts.api.SecurityType security_type, string symbol, DateTime expiration) {
this.security_type = security_type;
this.symbol = symbol;
this.expiration = expiration;
}
@@ -36,28 +42,31 @@ namespace mbts.analytics {
expiration = exp.expiration;
}
public SecurityExpiration to_security_expiration() {
// TODO
return new SecurityExpiration(Venue.Unset, SecurityType.Option, symbol, expiration);
}
public SecurityExpiration to_security_expiration(
Venue exchange = Venue.Unset, SecurityType type = SecurityType.Unset) =>
new(exchange, security_type, symbol, expiration);
[ProtoBuf.ProtoMember(10)]
public string symbol;
[ProtoBuf.ProtoMember(20)]
public DateTime expiration;
[ProtoBuf.ProtoMember(30)]
public bts.api.SecurityType security_type = bts.api.SecurityType.Option;
public bool Equals(VolSurfaceExpiration other) {
return other != null && symbol.Equals(other.symbol) && expiration.Equals(other.expiration);
}
public override int GetHashCode() { return symbol.GetHashCode() ^ expiration.GetHashCode(); }
public override int GetHashCode() { return security_type.GetHashCode() ^ symbol.GetHashCode() ^ expiration.GetHashCode(); }
public override bool Equals(object obj) {
return Equals(obj as VolSurfaceExpiration);
}
public override string ToString() {
return String.Format("{0} {1}", symbol, expiration.ToShortDateString());
return String.Format("{0} {1} {2}",
security_type.ToString().ToUpper().First(), symbol, expiration.ToShortDateString());
}
public int CompareTo(VolSurfaceExpiration other) {
@@ -68,15 +77,11 @@ namespace mbts.analytics {
}
public static class VolSurfaceExpirationExtensions {
public static SecurityExpiration ToSecurityExp(this VolSurfaceExpiration vs_exp) {
var type = SecurityType.Unset;
if (!string.IsNullOrWhiteSpace(vs_exp.symbol)) {
if (Char.IsLower(vs_exp.symbol.First())) type = SecurityType.Option;
else if (Char.IsUpper(vs_exp.symbol.First())) type = SecurityType.Future;
}
return new SecurityExpiration(Venue.Unset, type, vs_exp.symbol, vs_exp.expiration);
}
public static SecurityExpiration ToSecurityExp(
this VolSurfaceExpiration vs_exp, SecurityType type) =>
new(Venue.Unset, type, vs_exp.symbol, vs_exp.expiration);
}
public class VolSurfaceStrikeMap {
public readonly IDictionary<VolSurfaceExpiration, IEnumerable<double>> strike_map = null;
public VolSurfaceStrikeMap(IEnumerable<string> option_names, SystemContractData sc_data) {
@@ -1,4 +1,6 @@
using System;
using Spark.Core.Collections;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -17,11 +19,14 @@ namespace mbts.analytics
/// with default inputs
public static VolSurfaceInput sync_input_expirations_to_master_list(VolSurfaceInput vs_input, IEnumerable<VolSurfaceExpiration> system_exp_list)
{
HashSet<VolSurfaceExpiration> vs_exp_map = new HashSet<VolSurfaceExpiration>(vs_input.surface_parameters.curve_parameters_map.Select(t => t.Item1)),
sys_exp_map = new HashSet<VolSurfaceExpiration>(system_exp_list);
HashSet<VolSurfaceExpiration> deleted_exps, added_exps;
if (VolSurfaceUtilityFunctions.compare_hashsets(sys_exp_map, vs_exp_map, out deleted_exps, out added_exps))
{
var vs_exp_map = vs_input.surface_parameters.curve_parameters_map
.empty_if_null().Select(t => t.Item1).ToHashSet();
var sys_exp_map = system_exp_list.ToHashSet();
sys_exp_map.difference(
vs_exp_map,
out HashSet<VolSurfaceExpiration> deleted_exps,
out HashSet<VolSurfaceExpiration> added_exps);
if (deleted_exps.Any() || added_exps.Any()) {
VolSurfaceInput rv = VolSurfaceUtilityFunctions.clone_proto(vs_input);
rv.surface_parameters.curve_parameters_map = rv.surface_parameters.curve_parameters_map ?? new List<Tuple<VolSurfaceExpiration, VolCurveParameters>>();
rv.surface_parameters.curve_parameters_map.RemoveAll(t => deleted_exps.Contains(t.Item1));
@@ -100,7 +105,11 @@ namespace mbts.analytics
else if (vs_settings.core_settings.vol_surface_model == VolSurfaceEnums.VolSurfaceModel.Polynomial)
{
rv.spline_model_parameters = null;
rv.polynomial_model_parameters = rv.polynomial_model_parameters ?? new PolynomialModelVolCurveParameters() { atm_vol = Double.NaN, put_points = new List<Tuple<double, double>>(), call_points = new List<Tuple<double, double>>() };
rv.polynomial_model_parameters ??= new PolynomialModelVolCurveParameters() {
atm_vol = double.NaN
};
rv.polynomial_model_parameters.put_points ??= new();
rv.polynomial_model_parameters.call_points ??= new();
if (rv.polynomial_model_parameters.put_points.Count != vs_settings.polynomial_model_settings.n_put_points)
rv.polynomial_model_parameters.put_points = _sync_volpoints_to_settings(rv.polynomial_model_parameters.put_points, false, vs_settings.polynomial_model_settings.strike_axis, (int)vs_settings.polynomial_model_settings.n_put_points).ToList();
if (rv.polynomial_model_parameters.call_points.Count != vs_settings.polynomial_model_settings.n_call_points)
@@ -228,10 +237,8 @@ namespace mbts.analytics
return vs_input != null ? get_symbols(vs_input.surface_settings) : new string[] { };
}
public static IEnumerable<string> get_symbols(VolSurfaceSettings vs_settings)
{
return vs_settings.core_settings.symbol_pricing_model_map.Select(i => i.Item1);
}
public static IEnumerable<string> get_symbols(VolSurfaceSettings vs_settings) =>
vs_settings.core_settings.symbol_pricing_model_map.empty_if_null().Select(i => i.Item1);
public static VolCurveParameters get_curve_parameters(VolSurfaceInput vs_input, VolSurfaceExpiration exp)
{
@@ -675,4 +682,4 @@ namespace mbts.analytics
#endregion
}
}
}
@@ -0,0 +1,58 @@
namespace mbts.analytics {
using bts.utils;
using mbts.spark.filters;
using System;
public class VolSurfaceDriverTheo {
public static readonly VolSurfaceDriverTheo empty = new(
SecurityExpiration.empty, SecurityExpiration.empty);
public readonly SecurityExpiration exp;
public readonly SecurityExpiration driver_exp;
public readonly double market_price;
public readonly double driver_market_price;
public readonly double roll;
public readonly double theo;
public readonly double delta;
public readonly double settlement_price;
public readonly double settlement_theo;
public readonly double settlement_delta;
public VolSurfaceDriverTheo(
SecurityExpiration exp,
SecurityExpiration driver_exp,
double market_price = double.NaN,
double driver_market_price = double.NaN,
double roll = double.NaN,
double theo = double.NaN,
double delta = double.NaN,
double settlement_price = double.NaN,
double settlement_theo = double.NaN,
double settlement_delta = double.NaN
) {
this.exp = exp;
this.driver_exp = driver_exp;
this.market_price = market_price;
this.driver_market_price = driver_market_price;
this.roll = roll;
this.theo = theo;
this.delta = delta;
this.settlement_price = settlement_price;
this.settlement_theo = settlement_theo;
this.settlement_delta = settlement_delta;
}
public bool is_settlement_populated {
get {
bool non_populated = double.IsNaN(settlement_price) ||
Math.Abs(settlement_price) < 0.0000001;
return !non_populated;
}
}
public double effective_theo => is_settlement_populated ? settlement_price : theo;
public double effective_delta => is_settlement_populated ? 0 : delta;
}
}
File diff suppressed because it is too large. Load diff
@@ -5,6 +5,9 @@ using System.Text;
using System.Threading.Tasks;
using bts;
using bts.utils;
using mbts.utils;
namespace mbts.analytics
{
@@ -152,12 +155,8 @@ namespace mbts.analytics
out double adjusted_ref_fwd,
out double adjusted_ref_vol)
{
IComparer<ControlPoint> comp = VolSurfaceUtilityFunctions.get_comparer<ControlPoint>(
(cp1, cp2) =>
{
double d1 = Math.Abs(cp1.standard_strike), d2 = Math.Abs(cp2.standard_strike);
return (Double.IsNaN(d1) ? Double.PositiveInfinity : d1).CompareTo((Double.IsNaN(d2) ? Double.PositiveInfinity : d2));
});
var comp = new ComparerBuilder<ControlPoint>()
.to_comparer(cp => cp.standard_strike.abs().if_nan(double.PositiveInfinity));
adjusted_atm_vol = input_atm_vol + parallel_curve_move + (is_rebuild ? volpath_move : 0.0);
adjusted_put_points = calculated_controlpoints.Where(cp => cp.point_type == CoordinatesBasedModelHelper.ControlPoint.PointType.Put).OrderBy(cp => cp, comp).Select(cp => Tuple.Create(cp.input_strike, cp.input_abstract_vol));
adjusted_call_points = calculated_controlpoints.Where(cp => cp.point_type == CoordinatesBasedModelHelper.ControlPoint.PointType.Call).OrderBy(cp => cp, comp).Select(cp => Tuple.Create(cp.input_strike, cp.input_abstract_vol));
@@ -306,12 +305,8 @@ namespace mbts.analytics
IEnumerable<ControlPoint> calculated_controlpoints)
{
curve_parameters = VolSurfaceUtilityFunctions.clone_proto(curve_parameters);
IComparer<ControlPoint> comp = VolSurfaceUtilityFunctions.get_comparer<ControlPoint>(
(cp1, cp2) =>
{
double d1 = Math.Abs(cp1.standard_strike), d2 = Math.Abs(cp2.standard_strike);
return (Double.IsNaN(d1) ? Double.PositiveInfinity : d1).CompareTo((Double.IsNaN(d2) ? Double.PositiveInfinity : d2));
});
var comp = new ComparerBuilder<ControlPoint>()
.to_comparer(cp => cp.standard_strike.abs().if_nan(double.PositiveInfinity));
var adjusted_put_points = calculated_controlpoints.Where(cp => cp.point_type == CoordinatesBasedModelHelper.ControlPoint.PointType.Put).OrderBy(cp => cp, comp).Select(cp => Tuple.Create(cp.input_strike, cp.input_abstract_vol));
var adjusted_call_points = calculated_controlpoints.Where(cp => cp.point_type == CoordinatesBasedModelHelper.ControlPoint.PointType.Call).OrderBy(cp => cp, comp).Select(cp => Tuple.Create(cp.input_strike, cp.input_abstract_vol));
if (surface_settings.core_settings.vol_surface_model == VolSurfaceEnums.VolSurfaceModel.CubicSpline)
@@ -467,4 +462,4 @@ namespace mbts.analytics
#endregion
}
}
}
@@ -1,65 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.ComponentModel;
namespace mbts.analytics {
using bts.api.analytics;
namespace mbts.analytics
{
/// move this out later
public enum VolSurfaceGreeks
{
/* *********************Primary Greeks*********************/
Vol,
Moneyness,
Theo,
Delta,
[Description("BSM Delta")]
BSMDelta,
FlatVolDelta,
Vega,
[Description("BSM Vega")]
BSMVega,
AdjustedVega, /// adjusted_vega = vega * (atm_vega/n_days_atm_vega)
Theta,
AdjustedTheta, /// what is that ? (its in slide)
RollRho,
DiscountRho,
TimeValue,
/* *********************Second Order*********************/
Gamma,
[Description("BSM Gamma")]
BSMGamma,
OEV,
[Description("BSM OEV")]
BSMOEV,
Vanna,
Volga,
Charm,
[Description("Vol/Und")]
DVolDUnd,
[Description("Vol²/DUnd²")]
D2VolDUnd2,
/* *********************Curve Operations******************/
[Description("Price/DRR")]
DPriceDRiskReversal,
[Description("Price/Strangle")]
DPriceDStrangle,
[Description("Price/Put Tilt")]
DPriceDPutTilt,
[Description("Price/Call Tilt")]
DPriceDCallTilt,
/* *********************Risk*******************************/
[Description("PnL")]
PNL,
ExpirationDelta
}
using System;
using System.Collections.Generic;
[ProtoBuf.ProtoContract(Name = "VolSurfaceStrikeTheo")]
public class VolSurfaceStrikeTheo
{
public class VolSurfaceStrikeTheo {
[ProtoBuf.ProtoMember(10)]
public DateTime exp;
[ProtoBuf.ProtoMember(20)]
@@ -73,9 +19,8 @@ namespace mbts.analytics
}
[ProtoBuf.ProtoContract(Name = "VolSurfaceSymbolTheos")]
public class VolSurfaceSymbolTheos
{
public class VolSurfaceSymbolTheos {
[ProtoBuf.ProtoMember(10)]
public List<VolSurfaceStrikeTheo> all_theos;
}
}
}
}
@@ -1,12 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Concurrent;
namespace mbts.analytics {
using bts.api.analytics;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace mbts.analytics
{
/// Computes greeks from VolMatrix
public class VolSurfaceTheoCalculator
{
@@ -26,27 +25,27 @@ namespace mbts.analytics
{VolSurfaceGreeks.Moneyness, (volmat, is_call) => volmat.standard_strike},
{VolSurfaceGreeks.Theo, (volmat, is_call) => compute_theo (volmat, is_call)},
{VolSurfaceGreeks.Delta, (volmat, is_call) => compute_delta (volmat, is_call)},
{VolSurfaceGreeks.BSMDelta, (volmat, is_call) => compute_bsm_delta (volmat, is_call)},
{VolSurfaceGreeks.Bsmdelta, (volmat, is_call) => compute_bsm_delta (volmat, is_call)},
{VolSurfaceGreeks.FlatVolDelta, (volmat, is_call) => compute_flatvol_delta (volmat, is_call)},
{VolSurfaceGreeks.Vega, (volmat, is_call) => compute_vega (volmat, is_call)},
{VolSurfaceGreeks.BSMVega, (volmat, is_call) => compute_bsm_vega (volmat)},
{VolSurfaceGreeks.Bsmvega, (volmat, is_call) => compute_bsm_vega (volmat)},
{VolSurfaceGreeks.Theta, (volmat, is_call) => compute_theta (volmat, is_call)},
{VolSurfaceGreeks.TimeValue, (volmat, is_call) => compute_time_value (volmat, is_call)},
{VolSurfaceGreeks.Gamma, (volmat, is_call) => compute_gamma (volmat, is_call)},
{VolSurfaceGreeks.BSMGamma, (volmat, is_call) => compute_bsm_gamma (volmat)},
{VolSurfaceGreeks.OEV, (volmat, is_call) => compute_oev (volmat, is_call)},
{VolSurfaceGreeks.BSMOEV, (volmat, is_call) => compute_bsm_oev (volmat, is_call)},
{VolSurfaceGreeks.Bsmgamma, (volmat, is_call) => compute_bsm_gamma (volmat)},
{VolSurfaceGreeks.Oev, (volmat, is_call) => compute_oev (volmat, is_call)},
{VolSurfaceGreeks.Bsmoev, (volmat, is_call) => compute_bsm_oev (volmat, is_call)},
{VolSurfaceGreeks.Vanna, (volmat, is_call) => compute_vanna (volmat, is_call)},
{VolSurfaceGreeks.Volga, (volmat, is_call) => compute_volga (volmat, is_call)},
{VolSurfaceGreeks.Charm, (volmat, is_call) => compute_charm (volmat, is_call)},
{VolSurfaceGreeks.DVolDUnd, (volmat, is_call) => compute_dVolDUnd (volmat)},
{VolSurfaceGreeks.D2VolDUnd2, (volmat, is_call) => compute_d2VolDUnd2 (volmat)},
{VolSurfaceGreeks.DvolDund, (volmat, is_call) => compute_dVolDUnd (volmat)},
{VolSurfaceGreeks.D2VolDund2, (volmat, is_call) => compute_d2VolDUnd2 (volmat)},
{VolSurfaceGreeks.DPriceDRiskReversal, (volmat, is_call) => compute_dPriceDRiskReversal (volmat, is_call)},
{VolSurfaceGreeks.DPriceDStrangle, (volmat, is_call) => compute_dPriceDStrangle (volmat, is_call)},
{VolSurfaceGreeks.DPriceDPutTilt, (volmat, is_call) => compute_dPriceDPutTilt (volmat, is_call)},
{VolSurfaceGreeks.DPriceDCallTilt, (volmat, is_call) => compute_dPriceDCallTilt (volmat, is_call)},
{VolSurfaceGreeks.DpriceDriskReversal, (volmat, is_call) => compute_dPriceDRiskReversal (volmat, is_call)},
{VolSurfaceGreeks.DpriceDstrangle, (volmat, is_call) => compute_dPriceDStrangle (volmat, is_call)},
{VolSurfaceGreeks.DpriceDputTilt, (volmat, is_call) => compute_dPriceDPutTilt (volmat, is_call)},
{VolSurfaceGreeks.DpriceDcallTilt, (volmat, is_call) => compute_dPriceDCallTilt (volmat, is_call)},
};
}
@@ -443,4 +442,4 @@ namespace mbts.analytics
}
}
}
}
}
@@ -1,65 +1,72 @@
using System;
using bts.api;
using bts.api.analytics;
#nullable enable
namespace mbts.analytics {
using bts.api.analytics;
using bts.utils;
using mbts.spark;
using System;
[Serializable]
public class AnalyticsExpirationParameters : IEquatable<AnalyticsExpirationParameters> {
public readonly SecurityExpiration security,
driver_security,
deliverable_security,
roll_schedule_expiration;
public readonly DriverCalculationType driver_calc_type =
DriverCalculationType.Direct;
public readonly double roll_target, riskless_rate, settlement_price;
public readonly double driver_addend, driver_factor,
driver_translation_target, delta_beta, vega_beta;
public static readonly AnalyticsExpirationParameters empty =
new(
SecurityExpiration.empty,
null,
SecurityExpiration.empty,
SecurityExpiration.empty,
double.NaN,
double.NaN,
double.NaN,
double.NaN,
double.NaN);
public static AnalyticsExpirationParameters empty =
new AnalyticsExpirationParameters(SecurityExpiration.empty,
SecurityExpiration.empty,
SecurityExpiration.empty,
SecurityExpiration.empty,
Double.NaN, Double.NaN, Double.NaN,
Double.NaN, Double.NaN);
public readonly ExpirationDriverImmutable driver;
public readonly double roll_target;
public readonly double riskless_rate;
public readonly double settlement_price;
public readonly double driver_addend;
public readonly double driver_factor;
public readonly double driver_translation_target;
public readonly double delta_beta;
public readonly double vega_beta;
readonly bts.api.domain.SecurityExpirationImmutable _security;
readonly bts.api.domain.SecurityExpirationImmutable _deliverable;
readonly bts.api.domain.SecurityExpirationImmutable _roll_schedule;
public AnalyticsExpirationParameters(
SecurityExpiration this_security,
SecurityExpiration this_driver_security,
SecurityExpiration this_deliverable_security,
SecurityExpiration this_roll_schedule_expiration,
double this_roll_target, double this_riskless_rate,
double this_settlement_price, double this_delta_beta,
double this_vega_beta) {
security = this_security;
driver_security = this_driver_security ?? SecurityExpiration.empty;
deliverable_security = this_deliverable_security ?? SecurityExpiration.empty;
roll_schedule_expiration = this_roll_schedule_expiration ??
SecurityExpiration.empty;
roll_target = this_roll_target;
riskless_rate = this_riskless_rate;
settlement_price = this_settlement_price;
delta_beta = this_delta_beta;
vega_beta = this_vega_beta;
SecurityExpiration security,
ExpirationDriverImmutable? driver,
SecurityExpiration? deliverable_security,
SecurityExpiration? roll_schedule_expiration,
double roll_target,
double riskless_rate,
double settlement_price,
double delta_beta,
double vega_beta
) {
_security = security.to_api_sec_expi();
deliverable_security ??= SecurityExpiration.empty;
roll_schedule_expiration ??= SecurityExpiration.empty;
this.driver = driver ?? new(new() {
TimeWeightedInterpolated = new()
});
_deliverable = deliverable_security.to_api_sec_expi();
_roll_schedule = roll_schedule_expiration.to_api_sec_expi();
this.roll_target = roll_target;
this.riskless_rate = riskless_rate;
this.settlement_price = settlement_price;
this.delta_beta = delta_beta;
this.vega_beta = vega_beta;
}
public AnalyticsExpirationParameters(ExpirationParameterEntryImmutable db_i) {
Func<ExpirationImmutable, DateTime> to_dt = (ExpirationImmutable e) =>
new DateTime((int)e.ExpirationYear, (int)e.ExpirationMonth,
(int)e.ExpirationDay);
security = new SecurityExpiration(db_i.Exchange,
db_i.SecurityType, db_i.Symbol, to_dt(db_i.Expiration));
driver_calc_type = db_i.DriverCalc;
driver_security = new SecurityExpiration(db_i.DriverExchange,
db_i.DriverSecurityType, db_i.DriverSymbol,
to_dt(db_i.DriverExpiration));
deliverable_security = new SecurityExpiration(db_i.DeliverableExchange,
db_i.DeliverableSecurityType, db_i.DeliverableSymbol,
to_dt(db_i.DeliverableExpiration));
roll_schedule_expiration = new SecurityExpiration(db_i.RollScheduleExchange,
db_i.RollScheduleSecurityType, db_i.RollScheduleSymbol,
to_dt(db_i.RollScheduleExpiration));
_security = db_i.SecurityExpiration;
_deliverable = db_i.Deliverable;
_roll_schedule = db_i.RollSchedule;
driver = db_i.Driver;
roll_target = db_i.RollTarget;
riskless_rate = db_i.RisklessRate;
settlement_price = db_i.SettlementPrice;
@@ -67,66 +74,41 @@ namespace mbts.analytics {
vega_beta = db_i.VegaBeta;
}
public bts.api.analytics.ExpirationParameterEntry to_exp_param_entry() {
Func<DateTime, Expiration> to_exp = (DateTime e) => {
Expiration rv = new Expiration();
rv.ExpirationDay = (uint)e.Day;
rv.ExpirationMonth = (uint)e.Month;
rv.ExpirationYear = (uint)e.Year;
return rv;
public SecurityExpiration security => _security.to_sec_exp();
public SecurityExpiration driver_security => driver.HasSecurity ?
driver.Security.to_sec_exp() : SecurityExpiration.empty;
public SecurityExpiration deliverable_security => _deliverable.to_sec_exp();
public SecurityExpiration roll_schedule_expiration => _roll_schedule.to_sec_exp();
public ExpirationParameterEntry to_exp_param_entry() =>
new() {
SecurityExpiration = _security.CloneToMutable(),
Driver = driver.CloneToMutable(),
Deliverable = _deliverable.CloneToMutable(),
RollSchedule = _roll_schedule.CloneToMutable(),
RollTarget = roll_target,
RisklessRate = riskless_rate,
SettlementPrice = settlement_price,
DeltaBeta = delta_beta,
VegaBeta = vega_beta
};
bts.api.analytics.ExpirationParameterEntry rv = new ExpirationParameterEntry();
rv.SecurityType = security.security_type;
rv.Symbol = security.symbol;
rv.Expiration = to_exp(security.expiration);
rv.Exchange = security.exchange;
rv.DriverSecurityType = driver_security.security_type;
rv.DriverSymbol = driver_security.symbol;
rv.DriverExpiration = to_exp(driver_security.expiration);
rv.DriverExchange = driver_security.exchange;
public bool Equals(AnalyticsExpirationParameters? other) =>
other is not null &&
security.Equals(other.security) &&
driver_security.safe_equals(other.driver_security) &&
deliverable_security.safe_equals(other.deliverable_security) &&
roll_schedule_expiration.safe_equals(other.roll_schedule_expiration) &&
roll_target.Equals(other.roll_target) &&
riskless_rate.Equals(other.riskless_rate) &&
settlement_price.Equals(other.settlement_price) &&
delta_beta.Equals(other.delta_beta) &&
vega_beta.Equals(other.vega_beta);
rv.DeliverableSecurityType = deliverable_security.security_type;
rv.DeliverableSymbol = deliverable_security.symbol;
rv.DeliverableExpiration = to_exp(deliverable_security.expiration);
rv.DeliverableExchange = deliverable_security.exchange;
public override bool Equals(object? obj) =>
Equals(obj as AnalyticsExpirationParameters);
rv.RollScheduleSecurityType = roll_schedule_expiration.security_type;
rv.RollScheduleSymbol = roll_schedule_expiration.symbol;
rv.RollScheduleExpiration = to_exp(roll_schedule_expiration.expiration);
rv.RollScheduleExchange = roll_schedule_expiration.exchange;
rv.RollTarget = roll_target;
rv.RisklessRate = riskless_rate;
rv.SettlementPrice = settlement_price;
rv.DeltaBeta = delta_beta;
rv.VegaBeta = vega_beta;
return rv;
}
public bool Equals(AnalyticsExpirationParameters other) {
return other != null &&
security.Equals(other.security) &&
_null_equal(driver_security, other.driver_security) &&
_null_equal(deliverable_security, other.deliverable_security) &&
_null_equal(roll_schedule_expiration, other.roll_schedule_expiration) &&
roll_target.Equals(other.roll_target) &&
riskless_rate.Equals(other.riskless_rate) &&
settlement_price.Equals(other.settlement_price) &&
delta_beta.Equals(other.delta_beta) &&
vega_beta.Equals(other.vega_beta);
}
public override bool Equals(object obj) {
return Equals(obj as AnalyticsExpirationParameters);
}
public override int GetHashCode() { return security.GetHashCode(); }
private static bool _null_equal(SecurityExpiration a, SecurityExpiration b) {
a = a == null ? null : (a.is_empty() ? null : a);
b = b == null ? null : (b.is_empty() ? null : b);
return (a == null && b == null) || (a != null && b != null && a.Equals(b));
}
public override int GetHashCode() =>
security.GetHashCode();
}
}
}
@@ -41,7 +41,7 @@ namespace mbts.analytics {
}
public IDictionary<mbts.SecurityTuple, double> get_cpp_map() {
return input.get_cpp_list().ToDictionary(i => new mbts.SecurityTuple(i.Item1, i.Item2, Venue.Unset), i => i.Item3);
return input.get_cpp_list().ToDictionaryCrushed(i => new mbts.SecurityTuple(i.Item1, i.Item2, Venue.Sim), i => i.Item3);
}
private static mbts.SecurityExpiration _unset = mbts.SecurityExpiration.empty;
@@ -59,4 +59,4 @@ namespace mbts.analytics {
return rv;
}
}
}
}
@@ -51,13 +51,12 @@ namespace mbts.analytics {
return null;
}
public IEnumerable<Tuple<SecurityType, string, double>> get_cpp_list() {
List<Tuple<SecurityType, string, double>> rv = new List<Tuple<SecurityType, string, double>>();
public IEnumerable<Tuple<SecurityType, string, double>> get_cpp_list() =>
// TODO, cpp
return
exp_input_map.ToList().Select(kv =>
new Tuple<SecurityType, string, double>(kv.Key.security_type, kv.Key.symbol, 1));
}
exp_input_map
.Select(kv => Tuple.Create(kv.Key.security_type, kv.Key.symbol, 1.0))
.Distinct()
.ToList();
public IDictionary<mbts.SecurityTuple, double> get_cpp_map() {
return get_cpp_list().ToDictionary(
@@ -68,4 +67,4 @@ namespace mbts.analytics {
return exp_input_map.Where(kv => filter(kv.Key)).ToDictionary(kv => kv.Key, kv => kv.Value.roll_target);
}
}
}
}
@@ -3,8 +3,13 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using bts.api.analytics;
using NUnit.Framework;
using Spark.Core.Protobuf;
namespace mbts.analytics
{
[TestFixture]
@@ -21,16 +26,16 @@ namespace mbts.analytics
VolSurfaceGreeks.Gamma,
VolSurfaceGreeks.Vol,
VolSurfaceGreeks.AdjustedVega,
VolSurfaceGreeks.OEV,
VolSurfaceGreeks.Oev,
VolSurfaceGreeks.Theta,
VolSurfaceGreeks.DPriceDRiskReversal,
VolSurfaceGreeks.DpriceDriskReversal,
VolSurfaceGreeks.Vanna,
VolSurfaceGreeks.BSMVega,
VolSurfaceGreeks.Bsmvega,
VolSurfaceGreeks.Moneyness,
};
Theos t = new Theos();
VolSurfaceUtilityFunctions.serialize_proto(t);
ProtobufSerializationHelper.serialize(t);
VolSurfaceTimer timer = new VolSurfaceTimer ();
List<VolSurfaceStrikeTheo> all_theos = new List<VolSurfaceStrikeTheo>();
@@ -65,7 +70,7 @@ namespace mbts.analytics
{
Console.WriteLine("\nStrikes {0} Handles {1} Total {2}", n_exps * 1.0 * (strike_end - strike_beg) / strike_inc, n_handles, n_handles * n_exps * 1.0 * (strike_end - strike_beg) / strike_inc);
byte[] uncomp, comp;
timer.start (); uncomp = VolSurfaceUtilityFunctions.serialize_proto(sym_theos); timer.stop();
timer.start (); uncomp = ProtobufSerializationHelper.serialize(sym_theos); timer.stop();
Console.WriteLine("Serialization time {0}", timer.last_interval_time_ms);
timer.start(); comp = VolSurfaceUtilityFunctions.compress(uncomp); timer.stop();
Console.WriteLine("Compression time {0}", timer.last_interval_time_ms);
@@ -122,4 +127,4 @@ namespace mbts.analytics
Console.WriteLine(String.Format("Min time {0} Max time {1} Median time {2} msecs", times.First(), times.Last(), times[times.Count / 2]));
}
}
}
}
@@ -0,0 +1,6 @@
#nullable enable
namespace mbts.ui {
interface ITemplateSelectorKey {
string key { get; }
}
}
@@ -0,0 +1,41 @@
#nullable enable
namespace mbts.ui {
using bts.collections;
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
[ContentProperty(nameof(Map))]
class KeyedTemplateSelector : DataTemplateSelector {
readonly KeyedCollection<TemplateSelectorKeyValue, object?> _map = new(kv => kv.Key);
public IList Map => _map;
public DataTemplate? Default { get; set; }
public bool TryMatchType { get; set; }
public override DataTemplate? SelectTemplate(object? item, DependencyObject container) {
if (item is null) {
return Default;
}
var k = _get_key(item);
return k is not null && _map.TryGetValue(k, out var result) ?
result.Value : Default;
}
object? _get_key(object? item) {
if (item is null) {
return null;
}
var key = item;
if (key is ITemplateSelectorKey tsk) {
key = tsk.key;
}
if (key is null && TryMatchType) {
key = item.GetType();
}
return key;
}
}
}
@@ -0,0 +1,11 @@
#nullable enable
namespace mbts.ui {
using System.Windows;
using System.Windows.Markup;
[ContentProperty(nameof(Value))]
class TemplateSelectorKeyValue {
public object? Key { get; set; }
public DataTemplate? Value { get; set; }
}
}
@@ -15,6 +15,7 @@ using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Windows;
using bts.api.analytics;
using BCG;
using Disposable = mbts.Disposable;
@@ -24,6 +25,9 @@ namespace bts {
private readonly IBus _bus;
private readonly AnalyticsService _analytics_service;
private readonly VolSurfaceBusManager _vs_manager;
private readonly SpreadManager _spread_manager;
private readonly SpreadCalculationSynchronizer _spread_calc;
IDisposable _dispose;
[ImportingConstructor]
@@ -32,6 +36,8 @@ namespace bts {
_bus = bus;
_analytics_service = analytics_service;
_vs_manager = new VolSurfaceBusManager(_bus, _analytics_service);
_spread_manager = new SpreadManager(_vs_manager.bb(), "xxx");
_spread_calc = new SpreadCalculationSynchronizer(_vs_manager.bb());
}
public void Dispose() =>
@@ -46,7 +46,7 @@ namespace bts {
return;
}
log.info($"received request to delete the following {keys.Count} securities: {string.Join(", ", keys)}");
var (orders, orders_success) = await _orders_model.security_order_groups.FirstAsyncTask(SparkUtils.DefaultTimeOut);
var (orders, orders_success) = await _orders_model.security_orders.FirstAsyncTask(SparkUtils.DefaultTimeOut);
if (!orders_success) {
var msg = "Unable to delete synthetic securities: " +
$"timed out waiting for orders table (must verify that a synthetic security does not have any working orders before it can be deleted).";
@@ -0,0 +1,94 @@
#nullable enable
namespace bts.daemons {
using bts.api;
using bts.utils;
using mbts;
using mbts.spark;
using mbts.ui;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
[Export(typeof(IShellDaemon))]
public sealed class FakeSymbolDriverDaemon : IShellDaemon, IDisposable {
IDisposable _dispose;
public FakeSymbolDriverDaemon(IBus bus) {
int tid_counter = 1;
IDictionary<int, string> vol_surfaces = new Dictionary<int, string>();
var sec_trades = new Dictionary<uint, List<ITradeLogRow>>();
_dispose = Disposable.Create(
bus.subscribe(SparkTags.VolSurfaceListTag).Subscribe(vss => vol_surfaces = vss),
bus.subscribe(SparkTags.SecuritiesTag).SubscribeEach(secs => {
var btc_secs = secs.Values.Where(
s => s.security.Symbol == "BTC" &&
s.security.ContractCase == Security.ContractOneofCase.Future)
.ToList();
var fake_trades = btc_secs.Select(
s => get_fake_trade(to_sec_exp(s.security), 4200)).ToList();
bus.post(SparkTags.TradeLogTag, fake_trades);
var bbo_upd_refs = btc_secs.ToDictionary(s => s.security.Id, _ => 0UL);
var driver_sym_prices = btc_secs.ToImmutableDictionary(
s => to_sec_exp(s.security), get_driver_price);
double get_driver_price(SecurityMD smd) {
var upd_ref = bbo_upd_refs[smd.security.Id];
var rv = double.NaN;
if (smd.md.get_bbo(ref upd_ref, out var bid, out var ask)) {
rv = bid.price.if_nan(ask.price);
}
bbo_upd_refs[smd.security.Id] = upd_ref;
return rv;
}
return Observable.Interval(TimeSpan.FromSeconds(2)).Subscribe(_ => {
var bd = driver_sym_prices.ToBuilder();
foreach (var sec in btc_secs) {
var sec_exp = to_sec_exp(sec.security);
bd[sec_exp] = get_driver_price(sec).if_nan(driver_sym_prices[sec_exp]);
}
driver_sym_prices = bd.ToImmutable();
foreach (var vsid in vol_surfaces.Keys) {
bus.post(SparkTags.VolSurfaceDriverSymbolPriceTag(vsid), driver_sym_prices);
}
});
}));
static SecurityExpiration to_sec_exp(SecurityImmutable sec) =>
new(sec.Exchange, sec.ContractCase, sec.Symbol, sec.security_expiration() ?? DateTime.MinValue, sec.Id);
ITradeLogRow get_fake_trade(
SecurityExpiration sec_exp,
double price,
int size = 1,
string account = "ACC A",
double? strike = null,
PutOrCall? cp = null,
double? theo = null
) {
var t1 = new FakeTradeLogRow(
Interlocked.Increment(ref tid_counter),
sec_exp,
strike,
cp,
size,
price,
theo ?? price + 10 * new Random().NextDouble(),
account,
true,
DateTime.Now,
"FakeTrader");
return t1;
}
}
public void Dispose() =>
Disposable.dispose(ref _dispose);
}
}
+147 -70
View File
@@ -1,70 +1,147 @@
using bts.api;
using bts.api.synthetic;
using bts.md;
using mbts;
using mbts.co2;
using mbts.spark;
using mbts.ui;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using SecurityKey = System.UInt32;
namespace bts {
[Export(typeof(IInitializable))]
class MDDaemon : md.MDSource, IObserver<List<SecurityAndHandle>>, IInitializable, IDisposable {
readonly Lazy<IBus> _bus;
readonly Lazy<AuthTokenImmutable> _token;
readonly Lazy<SyntheticSecurityService> _ss;
readonly Dictionary<SecurityKey, SecurityMD> _deleted_synthetics = new Dictionary<SecurityKey, SecurityMD>();
[ImportingConstructor]
public MDDaemon(Lazy<IBus> bus, Lazy<AuthTokenImmutable> token, Lazy<SyntheticSecurityService> ss, Lazy<UserTuple> user)
: base(mbts.config.Configuration.get<md.RelayOptions>().naggle_ms, MDSourceOptions.DeferInit, user.Value) {
_bus = bus;
_token = token;
_ss = ss;
}
public int priority => 55;
[Export]
public MDConsumer consumer => _consumer;
IBus bus => _bus.Value;
public override void initialize() {
_relay.set_token(_token.Value);
_dispose.Add(
_ss.Value.subscribei_metadata()
.Select(upd => upd.all.Where(i => i.HasStrategy).ToDictionary(i => i.SecurityKey, i => i.Strategy))
.Subscribe(t => {
var deleted_synthetic_keys = new HashSet<uint>(t.Where(kv => kv.Value.Deleted).Select(kv => kv.Key));
// add back 'undeleted' synthetics
foreach (var kvp in _deleted_synthetics.ToList()) {
if (!deleted_synthetic_keys.Contains(kvp.Key)) {
_exchange_sec_map.TryAdd(kvp.Key, kvp.Value);
_deleted_synthetics.Remove(kvp.Key);
_version = DateTime.UtcNow;
}
}
// Remove any newly deleted synthetics and store them for potential undelete
foreach (var key in deleted_synthetic_keys) {
if (_exchange_sec_map.TryRemove(key, out SecurityMD deleted)) {
_deleted_synthetics[key] = deleted;
_version = DateTime.UtcNow;
}
}
// Post full dictionary of syntheics here
bus.post(SparkTags.SyntheticstrategiesTag, t);
}));
_dispose.Add(on_securities.Subscribe(md => bus.post(SparkTags.ServerSecuritiesTag, md)));
Task.Run(run);
}
}
}
#nullable enable
namespace bts {
using bts.api;
using bts.api.domain;
using bts.api.synthetic;
using bts.md;
using bts.spark;
using bts.utils;
using mbts;
using mbts.co2;
using mbts.config;
using mbts.spark;
using mbts.ui;
using Spark.Core.Data;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Reactive.Linq;
using SecurityKey = System.UInt32;
[Export(typeof(IInitializable))]
class MDDaemon : IInitializable, IDisposable {
readonly Lazy<IBus> _bus_backing;
readonly Lazy<UserTuple> _user;
readonly Lazy<AuthTokenImmutable> _token;
readonly Lazy<SyntheticSecurityService> _ss;
readonly Lazy<MDSource> _md_source_backing;
readonly ISecurityMetadataStore _security_metadata;
readonly TimeSpan _relay_throttle;
readonly TimeSpan _output_throttle;
readonly List<IDisposable> _resources = new(2);
[ImportingConstructor]
public MDDaemon(
Lazy<IBus> bus,
Lazy<AuthTokenImmutable> token,
Lazy<SyntheticSecurityService> ss,
Lazy<UserTuple> user,
ISecurityMetadataStore security_metadata)
: this(
bus,
token,
ss,
user,
security_metadata,
TimeSpan.FromMilliseconds(Configuration.get<RelayOptions>().naggle_ms),
TimeSpan.FromSeconds(1)) { }
public MDDaemon(
Lazy<IBus> bus,
Lazy<AuthTokenImmutable> token,
Lazy<SyntheticSecurityService> ss,
Lazy<UserTuple> user,
ISecurityMetadataStore security_metadata,
TimeSpan relay_throttle,
TimeSpan output_throttle
) {
_bus_backing = bus;
_user = user;
_token = token;
_ss = ss;
_relay_throttle = relay_throttle;
_output_throttle = output_throttle;
_security_metadata = security_metadata;
_md_source_backing = new(() => new(_user.Value, _relay_throttle, _output_throttle));
}
public int priority => 55;
[Export]
public MDConsumer consumer => _md_source.consumer;
MDSource _md_source => _md_source_backing.Value;
IBus _bus => _bus_backing.Value;
public void initialize() {
_md_source.set_token(_token.Value);
var synth_src = _ss.Value.subscribei_metadata()
.Select(upd => upd.all.Where(m => m.HasStrategy)
.ToDictionary(m => m.SecurityKey, m => m.Strategy))
.Replay(1)
.RefCount();
// post synth strategies to bus
_resources.Add(synth_src.Subscribe(_bus.post_callback(SparkTags.SyntheticstrategiesTag)));
// state required to detect 'undeleted' synthetics on updates, and add them back to the
// security map
var deleted_synth_cache = new Dictionary<SecurityKey, SecurityMD>();
var last_synth_strategies = new Dictionary<SecurityKey, ExecutionStrategyImmutable>();
var synth_id_comparer =
EqualityComparer.Create<KeyValuePair<SecurityKey, ExecutionStrategyImmutable>, SecurityKey>(
kv => kv.Key);
_resources.Add(
_md_source.subscribe_securities().CombineLatest(
synth_src.StartWith(new Dictionary<SecurityKey, ExecutionStrategyImmutable>()))
.BufferLatest(_output_throttle)
.Subscribe(upd => on_md(upd.First, upd.Second)));
void on_md(
ConcurrentDictionary<SecurityKey, SecurityMD> exch_secs,
Dictionary<SecurityKey, ExecutionStrategyImmutable> synth_strategies
) {
synth_strategies.Where(kv => kv.Value.Deleted).difference_hard(
last_synth_strategies.Where(kv => kv.Value.Deleted),
out var deleted_synths,
out var undeleted_synths,
synth_id_comparer);
last_synth_strategies = synth_strategies;
// add back 'undeleted' synthetics
foreach (var (id, strategy) in undeleted_synths) {
if (deleted_synth_cache.TryPopValue(id, out var synth)) {
exch_secs.TryAdd(id, synth);
}
}
// remove newly deleted synthetics, and store them for potential undelete
foreach (var (id, _) in deleted_synths) {
if (exch_secs.TryRemove(id, out var deleted)) {
deleted_synth_cache[id] = deleted;
}
}
// set 'unit quantity' for each sec
foreach (var smd in exch_secs.Values) {
var meta = _security_metadata.get(smd.security);
if (meta.HasValue) {
exch_secs[smd.id] = new(
smd.security, smd.md, meta.Value.PriceDisplay, meta.Value.QuantityDisplay);
}
}
_bus.post(SparkTags.ServerSecuritiesTag, exch_secs);
}
}
public void Dispose() =>
Disposable.dispose(_resources);
}
}
+11 -1
View File
@@ -66,7 +66,17 @@ namespace bts {
}
private void _merge_and_post() {
Dictionary<uint, SecurityMD> to_pub = new Dictionary<uint, SecurityMD>(_server_sec_map);
Func<SecurityMD, bool> is_active = (sec_md) => {
if (sec_md.security.HasFuture || sec_md.security.HasOption) {
var exp = sec_md.security.security_expiration();
if (exp.HasValue) {
return exp.Value.Date >= DateTime.Now.Date.AddDays(-1);
}
return true;
}
return true;
};
var to_pub = _server_sec_map.Where(kv => is_active(kv.Value)).ToDictionary(kv => kv.Key, kv => kv.Value);
foreach (var kv in _fake_sec_map) {
to_pub[kv.Key] = kv.Value;
}
+42 -13
View File
@@ -5,6 +5,7 @@ using bts.spark;
using mbts;
using mbts.config;
using mbts.persist;
using mbts.spark;
using mbts.ui;
using mbts.ui.spark;
@@ -23,6 +24,7 @@ namespace bts.shell {
class OrderTicketDaemon : IShellDaemon {
readonly IBus _bus;
readonly OrdersModel _model;
readonly UserSettingsHub _settings_hub;
readonly ErrorReporter _error_reporter;
readonly bool _close_on_send;
IReadOnlyDictionary<uint, SecurityMD> _md_map;
@@ -30,12 +32,13 @@ namespace bts.shell {
IDisposable _dispose;
[ImportingConstructor]
public OrderTicketDaemon(IBus bus, OrdersModel model, ErrorReporter error_reporter)
: this(bus, model, error_reporter, Configuration.get<bts.config.OrderTicketOptions>().close_on_send) { }
public OrderTicketDaemon(IBus bus, OrdersModel model, UserSettingsHub settings_hub, ErrorReporter error_reporter)
: this(bus, model, settings_hub, error_reporter, Configuration.get<bts.config.OrderTicketOptions>().close_on_send) { }
public OrderTicketDaemon(IBus bus, OrdersModel model, ErrorReporter error_reporter, bool close_on_send) {
public OrderTicketDaemon(IBus bus, OrdersModel model, UserSettingsHub settings_hub, ErrorReporter error_reporter, bool close_on_send) {
_bus = bus;
_model = model;
_settings_hub = settings_hub;
_error_reporter = error_reporter;
_close_on_send = close_on_send;
_dispose = Disposable.Create(
@@ -62,22 +65,39 @@ namespace bts.shell {
window.Show(-200, -160, true);
}
void _show_order_ticket(SecurityMD smd) =>
void _show_order_ticket(SecurityMD smd) {
var settings_src = _settings_hub.subscribe_default_settings()
.Select(s => s.get_ladder_profile(smd.security)?.value ?? LadderSettings.Default);
_show_order_window(new OrderTicket {
DataContext = new NewOrderTicketVM(_model, smd,
Observable.Return(LadderSettings.Default)) {
DataContext = new NewOrderTicketVM(_model, smd, settings_src) {
close_on_send = _close_on_send
}
});
}
void _show_order_ticket((OrderDefinitionImmutable def, double price, uint size) ops) {
if (_md_map.TryGetValue(ops.def.SecurityKey, out SecurityMD smd))
_show_order_window(new OrderTicket {
DataContext = new NewOrderTicketVM(_model, smd, ops.def, ops.price, ops.size,
Observable.Return(LadderSettings.Default.calculator_buttons)) {
close_on_send = _close_on_send
}
});
var (def, price, size) = ops;
if (!_md_map.TryGetValue(def.SecurityKey, out SecurityMD smd)) {
return;
}
if (def.Account.is_null_or_empty() && def.AccountId == 0) {
var settings = _settings_hub.current.get_ladder_profile(smd.security);
var default_account = settings?.value?.default_account;
if (default_account.HasValue) {
var mdef = def.CloneToMutable();
// The order ticket will resolve AccountId to a name
mdef.AccountId = default_account.Value;
def = new(mdef);
}
}
_show_order_window(new OrderTicket {
DataContext = new NewOrderTicketVM(_model, smd, def, price, size,
Observable.Return(LadderSettings.Default.calculator_buttons)) {
close_on_send = _close_on_send
}
});
}
void _show_order_tickets(IImmutableSet<uint> securities) {
@@ -99,5 +119,14 @@ namespace bts.shell {
});
}
}
LadderSettings _get_settings(SecurityImmutable sec) {
var settings = _settings_hub.current;
if (settings.ladder_profiles.TryGetFirst(
lsp => lsp.security_criteria.includes(sec), out var lsp)) {
return lsp.value;
}
return null;
}
}
}
+172
View File
@@ -0,0 +1,172 @@
#nullable enable
namespace bts.daemons {
using bts.api;
using bts.api.analytics;
using bts.api.core;
using bts.api.orderman;
using bts.api.position;
using bts.spark;
using mbts;
using mbts.analytics;
using mbts.spark;
using mbts.ui;
using Spark.Core.Collections;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
[Export(typeof(IShellDaemon))]
public sealed class ReportDaemon : IShellDaemon, IDisposable {
readonly ConcurrentFactory<int, IDisposable> _report_calculators;
readonly AnalyticsService _analytics_service;
readonly PositionService _position_service;
readonly OrderService _order_service;
readonly ErrorReporter _error_reporter;
readonly IBus _bus;
IReadOnlyDictionary<int, ReportImmutable> _report_parameters_map =
new Dictionary<int, ReportImmutable>();
IDisposable _dispose;
[ImportingConstructor]
public ReportDaemon(
IBus bus,
AnalyticsService analytics_service,
PositionService position_service,
OrderService order_service,
ErrorReporter error_reporter
) {
_bus = bus;
_analytics_service = analytics_service;
_position_service = position_service;
_error_reporter = error_reporter;
_order_service = order_service;
_report_calculators = new(mk_report_calculator);
_dispose = Disposable.Create(
bus.subscribe(SparkTags.ReportBlackboardTags.Create).Subscribe(rp => _create_report(rp).ignore()),
bus.subscribe(SparkTags.ReportBlackboardTags.Save).Subscribe(rp => _save_report(rp).ignore()),
bus.subscribe(SparkTags.ReportBlackboardTags.Delete).Subscribe(id => _delete_report(id).ignore()),
bus.subscribe(SparkTags.ReportBlackboardTags.Activate).Subscribe(_activate_report),
bus.subscribe(SparkTags.ReportBlackboardTags.Deactivate).Subscribe(_deactivate_report),
_analytics_service.subscribei_reports().Table().Subscribe(_on_reports),
_bus.subscribe(SparkTags.SystemContractsTag).CombineLatest(
_order_service.subscribe_fills(), _position_service.subscribe_manual_fills())
.Subscribe(tup => _on_all_trade_data(tup.First, tup.Second, tup.Third)),
_report_calculators);
IDisposable mk_report_calculator(int id) {
if (!_report_parameters_map.TryGetValue(id, out var r)) {
Log.Gen.warn($"ReportDaemon failed to find report for id {id}");
return Disposable.empty;
}
Log.Gen.info(
$"Activating report calculator for {fmt_rep_title(r)}");
var calc = r.ReportType switch {
Report.Types.ReportType.Slide => new SlideReportCalculator(_bus, r),
Report.Types.ReportType.Combo => new ComboReportCalculator(
_bus, r, TimeSpan.FromSeconds(1)),
_ => Disposable.empty
};
return Disposable.Create(() => {
r = _report_parameters_map.GetValueOrDefault(id, r);
Log.Gen.info(
$"Deactivating report calculator for {fmt_rep_title(r)}");
Disposable.dispose(ref calc);
});
}
static string fmt_rep_title(ReportImmutable r) =>
$"{r.ReportType} '{r.ReportName}' (id: {r.Id})";
}
public void Dispose() =>
Disposable.dispose(ref _dispose);
void _on_reports(TableUpdate<ReportImmutable, int> reports) {
_report_parameters_map = reports.state;
// recreate calculators with new/changed parameters
foreach (var r in reports.added.Concat(reports.changes.New())) {
if (_report_calculators.Remove(r.Id)) {
_report_calculators.get_or_add(r.Id);
}
}
_bus.post(SparkTags.ReportBlackboardTags.ListTag, _report_parameters_map);
}
async Task _create_report(ReportImmutable report) {
Log.Gen.info($"Creating report: {report}");
var (new_id, success) = await _error_reporter.safe_execute(
() => _analytics_service.get_new_report_id_async(new VoidMessage()),
reply => reply.Ok,
reply => string.Empty,
"creating report");
var mreport = report.CloneToMutable();
mreport.Id = new_id.NewId;
report = new(mreport);
await _save_report(report);
}
Task _save_report(ReportImmutable report) {
Log.Gen.info($"Saving report: {report}");
return _error_reporter.safe_execute(
() => _analytics_service.save_report_async(report),
rm => rm.Success,
rm => rm.ErrorMessage,
"saving report");
}
Task _delete_report(int id) {
Log.Gen.info($"Deleting report: id={id}");
return _error_reporter.safe_execute(
() => _analytics_service.delete_report_async(
new IntWrapperImmutable(new() { Data = id })),
rm => rm.Success,
rm => rm.ErrorMessage,
"deleting report");
}
void _on_all_trade_data(
SystemContractData sc_data, Update<Fill, string> fills, Update<ManualFill, int> man_fills) {
if (sc_data is null) {
return;
}
var fills_filtered = fills.all.Where(f => sc_data.sec_md_map.ContainsKey(f.SecurityKey));
if (fills.all.Count() > fills_filtered.Count()) {
Log.Ui.error(
$"ReportDaemon {fills.all.Count() - fills_filtered.Count()} fills could not be " +
"resolved");
}
var man_fills_filtered = man_fills.all
.Where(m => sc_data.sec_md_map.ContainsKey(m.SecurityKey));
if (man_fills.all.Count() > man_fills_filtered.Count()) {
Log.Ui.error(
$"ReportDaemon {man_fills.all.Count() - man_fills_filtered.Count()} manual fills " +
"could not be resolved");
}
var fills_tl = fills_filtered.Select(
f => new TradeLogRow(f, sc_data.sec_md_map[f.SecurityKey].security));
var m_fills_tl = man_fills_filtered.Select(
m => new TradeLogRow(m, sc_data.sec_md_map[m.SecurityKey].security));
var merged_fills = fills_tl.Concat(m_fills_tl).ToList();
Log.Ui.info($"ReportDaemon posting {merged_fills.Count} trades");
_bus.post(SparkTags.TradeLogTag, merged_fills);
}
void _activate_report(int id) =>
_report_calculators.get_or_add(id);
void _deactivate_report(int id) =>
_report_calculators.Remove(id);
}
}
+479 -279
View File
@@ -1,279 +1,479 @@
using bts;
using mbts.ui.dpi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace mbts.ui {
public class Icons {
public static class Smashicons {
public static readonly string
AddFileGeometryKey = _fmt("AddFile"),
EditDocumentGeometryKey = _fmt("EditDocument"),
DeleteDocumentGeometryKey = _fmt("DeleteDocument"),
SaveGeometryKey = _fmt("Save");
static string _fmt(string name) =>
$"{nameof(Smashicons)}.{name}.GeometryKey";
}
public const string
AddBoxesGeometryKey = nameof(AddBoxesGeometryKey),
AddFileGeometryKey = nameof(AddFileGeometryKey),
AddFileThinGeometryKey = nameof(AddFileThinGeometryKey),
AttachAlgosKey = nameof(AttachAlgosKey),
CheckMarkGeometryKey = nameof(CheckMarkGeometryKey),
CopyWFGeometryKey = nameof(CopyWFGeometryKey),
CopyBoxesGeometryKey = nameof(CopyBoxesGeometryKey),
CurrencyExchangeGeometryKey = nameof(CurrencyExchangeGeometryKey),
DataEditGeometryKey = nameof(DataEditGeometryKey),
DetachAlgosKey = nameof(DetachAlgosKey),
DiskGeometryKey = nameof(DiskGeometryKey),
DiskFileGeometryKey = nameof(DiskFileGeometryKey),
DocumentGeometryKey = nameof(DocumentGeometryKey),
DocumentAddGeometryKey = nameof(DocumentAddGeometryKey),
DocumentBrokenGeometryKey = nameof(DocumentBrokenGeometryKey),
DocumentCopyGeometryKey = nameof(DocumentCopyGeometryKey),
DocumentEmptyGeometryKey = nameof(DocumentEmptyGeometryKey),
DocumentPairGeometryKey = nameof(DocumentPairGeometryKey),
DocumentStarGeometryKey = nameof(DocumentStarGeometryKey),
DraggableGeometryKey = nameof(DraggableGeometryKey),
EditDocumentAltGeometryKey = nameof(EditDocumentAltGeometryKey),
EditDocumentGeometryKey = nameof(EditDocumentGeometryKey),
GearGeometryKey = nameof(GearGeometryKey),
HamburgerMenuGeometryKey = nameof(HamburgerMenuGeometryKey),
HornGeometryKey = nameof(HornGeometryKey),
KeyGeometryKey = nameof(KeyGeometryKey),
LetterAKey = nameof(LetterAKey),
LetterDKey = nameof(LetterDKey),
MenuOrientationGeometryKey = nameof(MenuOrientationGeometryKey),
OrdersGeometryKey = nameof(OrdersGeometryKey),
PauseGeometryKey = nameof(PauseGeometryKey),
PaymentGeometryKey = nameof(PaymentGeometryKey),
PencilGeometryKey = nameof(PencilGeometryKey),
PlayGeometryKey = nameof(PlayGeometryKey),
ProhibitedGeometryKey = nameof(ProhibitedGeometryKey),
RubberStampGeometryKey = nameof(RubberStampGeometryKey),
SpeakerGeometryKey = nameof(SpeakerGeometryKey),
StarGeometryKey = nameof(StarGeometryKey),
ToolsGeometryKey = nameof(ToolsGeometryKey),
TrashGeometryKey = nameof(TrashGeometryKey),
UndoCircularGeometryKey = nameof(UndoCircularGeometryKey),
WarningExclamationGeometryKey = nameof(WarningExclamationGeometryKey),
WarningGeometryKey = nameof(WarningGeometryKey);
public static Geometry PlayGeometry => Geometry.Parse(get_geometric_path(PlayGeometryKey).FirstOrDefault() ?? string.Empty);
static readonly Pen _copy_boxes_pen = new Pen(Brushes.Black, HighDpiExtensions.RoundLayoutValue(5)).frozen();
static readonly string base_uri = "pack://application:,,,/Images/Icons/";
private static ResourceDictionary _resources = (ResourceDictionary)Application.LoadComponent(new Uri("/Images/Vector/Icons.xaml", UriKind.RelativeOrAbsolute));
private static Uri uri(string filename) {
return new Uri(base_uri + filename);
}
[Obsolete("Please only add new vector icons using icons.xaml")]
private static ImageSource load_image(string filename) {
return new BitmapImage(uri(filename)).frozen();
}
private static ImageSource load_resource_and_freeze(string resource_name) {
lock (_resources) {
return ((DrawingImage)_resources[resource_name]).frozen();
}
}
#pragma warning disable CS0618 // Type or member is obsolete
public static ImageSource Logo { get { return load_image("logo.ico"); } }
public static ImageSource Admin { get { return load_resource_and_freeze("Admin"); } }
public static ImageSource Analytics { get { return load_resource_and_freeze("Analytics"); } }
public static ImageSource Sheets { get { return load_resource_and_freeze("Sheets"); } }
public static ImageSource Trades { get { return load_resource_and_freeze("Trades"); } }
public static ImageSource Depth { get { return load_resource_and_freeze("Depth"); } }
public static ImageSource Ladder { get { return load_resource_and_freeze("Ladder"); } }
public static ImageSource SheetsRed { get { return load_image("SheetsRed.png"); } }
public static ImageSource SheetsGreen { get { return load_image("SheetsGreen.png"); } }
public static ImageSource Spreads { get { return load_resource_and_freeze("Spreads"); } }
public static ImageSource BlueSpreads { get { return load_image("BlueSpread.ico"); } }
public static ImageSource Reports { get { return load_resource_and_freeze("Reports"); } }
public static ImageSource Risk { get { return load_resource_and_freeze("Risk"); } }
public static ImageSource Eye { get { return load_resource_and_freeze("Eye"); } }
public static ImageSource Coins { get { return load_resource_and_freeze("Coins"); } }
public static ImageSource DataCopy { get { return load_image("DataCopy.ico"); } }
public static ImageSource Refresh { get { return load_image("Refresh.png"); } }
public static ImageSource FavoriteWindow { get { return load_image("FavoriteWindow.png"); } }
public static ImageSource Browser => load_resource_and_freeze("Browser");
public static ImageSource Date { get { return load_image("Date.png"); } }
public static ImageSource Cube3d { get { return load_resource_and_freeze("Cube"); } }
public static ImageSource Algo { get { return Cube3d; } }
public static ImageSource Quote { get { return Math; } }
public static ImageSource Math { get { return load_resource_and_freeze("Surface"); } }
public static ImageSource Abacus { get { return load_image("Abacus.png"); } }
public static ImageSource Delete { get { return load_image("Delete.png"); } }
public static ImageSource Up_Arrow { get { return load_image("Arrowhead-Up.png"); } }
public static ImageSource Down_Arrow { get { return load_image("Arrowhead-Down.png"); } }
public static ImageSource Zoom_In { get { return load_image("Zoom-In.png"); } }
public static ImageSource Zoom_Out { get { return load_image("Zoom-Out.png"); } }
public static ImageSource InsertionArrow { get { return load_image("InsertionArrow.png"); } }
#pragma warning restore CS0618
// Vector icons
public static ImageSource Bookmarks { get { return load_resource_and_freeze("Bookmarks"); } }
public static ImageSource Window { get { return load_resource_and_freeze("Window"); } }
public static ImageSource ActiveWindow { get { return load_resource_and_freeze("ActiveWindow"); } }
public static ImageSource Crucible { get { return load_resource_and_freeze("Crucible"); } }
public static ImageSource Accounting { get { return load_resource_and_freeze("Accounting"); } }
public static ImageSource Add { get { return load_resource_and_freeze("Add"); } }
public static ImageSource AddBoxes => create_icon(AddBoxesGeometryKey);
public static ImageSource AddEncircled { get { return load_resource_and_freeze("AddEncircled"); } }
public static ImageSource AddFile => create_icon(Smashicons.AddFileGeometryKey);
public static ImageSource AttachAlgos => create_icon(AttachAlgosKey);
public static ImageSource Beaker { get { return load_resource_and_freeze("Beaker"); } }
public static ImageSource Book { get { return load_resource_and_freeze("Book"); } }
public static ImageSource Orders => create_icon(OrdersGeometryKey);
public static ImageSource AddOrders { get { return load_resource_and_freeze("AddOrders"); } }
public static ImageSource CancelOrders { get { return load_resource_and_freeze("CancelOrders"); } }
public static ImageSource CancelBuys { get { return load_resource_and_freeze("CancelBuys"); } }
public static ImageSource CancelSells { get { return load_resource_and_freeze("CancelSells"); } }
public static ImageSource CancelSelected { get { return load_resource_and_freeze("CancelSelected"); } }
public static ImageSource LadderCancelOrders { get { return load_resource_and_freeze("LadderCancelOrders"); } }
public static ImageSource LadderCancelBuys { get { return load_resource_and_freeze("LadderCancelBuys"); } }
public static ImageSource LadderCancelSells { get { return load_resource_and_freeze("LadderCancelSells"); } }
public static ImageSource Synthetics { get { return load_resource_and_freeze("Synthetics"); } }
public static ImageSource AddSynthetic { get { return load_resource_and_freeze("AddSynthetic"); } }
public static ImageSource RemoveSynthetic { get { return load_resource_and_freeze("RemoveSynthetic"); } }
public static ImageSource ModifySynthetic { get { return load_resource_and_freeze("ModifySynthetic"); } }
public static ImageSource CloneSynthetic { get { return load_resource_and_freeze("CloneSynthetic"); } }
public static ImageSource analytics => Math;
public static ImageSource ModifyOrder { get { return load_resource_and_freeze("ModifyOrder"); } }
public static ImageSource CheckMark => create_icon(CheckMarkGeometryKey);
public static ImageSource Clock { get { return load_resource_and_freeze("Clock"); } }
public static ImageSource CopyWF => create_icon(CopyWFGeometryKey);
public static ImageSource CopyBoxes => create_icon(CopyBoxesGeometryKey, null, _copy_boxes_pen);
public static ImageSource CurrencyExchange => create_icon(CurrencyExchangeGeometryKey);
public static ImageSource DataEdit => create_icon(DataEditGeometryKey);
public static ImageSource Defrag { get { return load_resource_and_freeze("Defrag"); } }
public static ImageSource DetachAlgos => create_icon_and_rotate(DetachAlgosKey, Brushes.Red);
public static ImageSource Disk => create_icon(DiskGeometryKey);
public static ImageSource DiskFile => create_icon(DiskFileGeometryKey);
public static ImageSource Display { get { return load_resource_and_freeze("Display"); } }
public static ImageSource DocumentAdd => create_icon(DocumentAddGeometryKey);
public static ImageSource DocumentBroken => create_icon(DocumentBrokenGeometryKey);
public static ImageSource DocumentCopy => create_icon(DocumentCopyGeometryKey);
public static ImageSource DocumentEmpty => create_icon(DocumentEmptyGeometryKey);
public static ImageSource DocumentPair => create_icon(DocumentPairGeometryKey);
public static ImageSource DocumentStar => create_icon(DocumentStarGeometryKey);
public static ImageSource Draggable => create_icon(DraggableGeometryKey);
public static ImageSource EditDocument => create_icon("Smashicons.EditDocument.GeometryKey");
public static ImageSource Export => load_resource_and_freeze("Export");
public static ImageSource Filter { get { return load_resource_and_freeze("Filter"); } }
public static ImageSource FilterActive { get { return load_resource_and_freeze("FilterActive"); } }
public static ImageSource FilterError { get { return load_resource_and_freeze("FilterError"); } }
public static ImageSource Gear => create_icon(GearGeometryKey);
public static ImageSource HamburgerMenu => create_icon(HamburgerMenuGeometryKey);
public static ImageSource Horn => create_icon(HornGeometryKey);
public static ImageSource Import => load_resource_and_freeze("Import");
public static ImageSource Key => create_icon(KeyGeometryKey);
public static ImageSource Knight { get { return load_resource_and_freeze("Knight"); } }
public static ImageSource MenuOrientation => create_icon(MenuOrientationGeometryKey);
public static ImageSource options_view => Sheets;
public static ImageSource Pause => create_icon(PauseGeometryKey);
public static ImageSource Payment => create_icon(PaymentGeometryKey);
public static ImageSource Pencil => create_icon(PencilGeometryKey);
public static ImageSource Play => create_icon(PlayGeometryKey);
public static ImageSource Prohibited => create_icon(ProhibitedGeometryKey);
public static ImageSource RubberStamp => create_icon(RubberStampGeometryKey);
public static ImageSource RedoCircular => create_icon(UndoCircularGeometryKey, Brushes.Black, null, new ScaleTransform(-1, 1));
public static ImageSource Spawn { get { return load_resource_and_freeze("Spawn"); } }
public static ImageSource Speaker => create_icon(SpeakerGeometryKey);
public static ImageSource Star => create_icon(StarGeometryKey);
public static ImageSource Target { get { return load_resource_and_freeze("Target"); } }
public static ImageSource Tetris { get { return load_resource_and_freeze("Tetris"); } }
public static ImageSource Tools => create_icon(ToolsGeometryKey);
public static ImageSource Trash => create_icon(TrashGeometryKey);
public static ImageSource Warning => create_icon(WarningGeometryKey, Brushes.IndianRed);
public static ImageSource WarningExclamation => create_icon(WarningExclamationGeometryKey, Brushes.IndianRed);
public static ImageSource UndoCircular => create_icon(UndoCircularGeometryKey);
public static ImageSource ViewSettings => load_resource_and_freeze("ViewSettings");
public static ImageSource vol_surface => Math;
public static ImageSource Wrench { get { return load_resource_and_freeze("Wrench"); } }
public static ImageSource RightArrow { get { return (load_resource_and_freeze("RightArrow")); } }
public static ImageSource DownArrow { get { return (load_resource_and_freeze("DownArrow")); } }
public static ImageSource Factory { get { return (load_resource_and_freeze("Factory")); } }
public static ImageSource DotsVertical { get { return (load_resource_and_freeze("DotsVertical")); } }
public static ImageSource HandPointingOverDocument => load_resource_and_freeze("HandPointingOverDocument");
public static ImageSource Support => load_resource_and_freeze("SupportIcon");
public static ImageSource FloppyDisk => create_icon("FloppyDisk");
public static ImageSource create_icon(string geometric_path_key) =>
create_icon(geometric_path_key, Brushes.Black);
public static ImageSource create_icon(string geometric_path_key, Brush brush, Pen pen = null, Transform transform = null) {
var rv = new DrawingImage(create_drawing(geometric_path_key, brush, pen, transform));
rv.Freeze();
return rv;
}
public static ImageSource create_icon_and_rotate(string geometric_path_key, Brush brush = null, Pen pen = null, Transform transform = null, double degrees = 90) {
if (brush == null) {
brush = Brushes.Black;
}
var drawing = create_drawing(geometric_path_key, brush, pen, transform);
var dg = new DrawingGroup();
dg.Children.Add(drawing);
dg.Transform = new RotateTransform(degrees);
var rv = new DrawingImage(dg);
rv.Freeze();
return rv;
}
public static Drawing create_drawing(string geometric_path_key) =>
create_drawing(geometric_path_key, Brushes.Black);
public static Drawing create_drawing(string geometric_path_key, Brush brush, Pen pen = null, Transform transform = null) =>
create_drawing(get_geometric_path(geometric_path_key), brush, pen, transform);
public static Drawing create_drawing(IEnumerable<string> paths, Brush brush, Pen pen = null, Transform transform = null) {
var drawing_group = new DrawingGroup();
foreach (string p in paths) {
drawing_group.Children.Add(new GeometryDrawing(brush, pen, Geometry.Parse(p)));
}
if (transform != null)
drawing_group.Transform = transform;
return drawing_group;
}
public static IEnumerable<string> get_geometric_path(string 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));
path = string.Empty;
}
return new[] { path };
} else if (obj is string[] paths) {
return paths.Where(p => !string.IsNullOrEmpty(p)).ToArray();
} else return null;
}
}
}
using bts;
using bts.collections;
using bts.utils;
using mbts.ui.dpi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace mbts.ui {
public class Icons {
public static class Smashicons {
public static readonly string
AddFileGeometryKey = _fmt("AddFile"),
EditDocumentGeometryKey = _fmt("EditDocument"),
DeleteDocumentGeometryKey = _fmt("DeleteDocument"),
SaveGeometryKey = _fmt("Save");
static string _fmt(string name) =>
$"{nameof(Smashicons)}.{name}.GeometryKey";
}
public const string
AddBoxesGeometryKey = nameof(AddBoxesGeometryKey),
AddFileGeometryKey = nameof(AddFileGeometryKey),
AddFileThinGeometryKey = nameof(AddFileThinGeometryKey),
ArrowGeometryKey = nameof(ArrowGeometryKey),
AttachAlgosKey = nameof(AttachAlgosKey),
CallPutGeometryKey = nameof(CallPutGeometryKey),
CandidateGeometryKey = nameof(CandidateGeometryKey),
CandidateWithAudienceGeometryKey = nameof(CandidateWithAudienceGeometryKey),
CheckMarkGeometryKey = nameof(CheckMarkGeometryKey),
CopyWFGeometryKey = nameof(CopyWFGeometryKey),
CopyBoxesGeometryKey = nameof(CopyBoxesGeometryKey),
CurrencyExchangeGeometryKey = nameof(CurrencyExchangeGeometryKey),
DataEditGeometryKey = nameof(DataEditGeometryKey),
DetachAlgosKey = nameof(DetachAlgosKey),
DiskGeometryKey = nameof(DiskGeometryKey),
DiskFileGeometryKey = nameof(DiskFileGeometryKey),
DocumentGeometryKey = nameof(DocumentGeometryKey),
DocumentAddGeometryKey = nameof(DocumentAddGeometryKey),
DocumentBrokenGeometryKey = nameof(DocumentBrokenGeometryKey),
DocumentCopyGeometryKey = nameof(DocumentCopyGeometryKey),
DocumentEmptyGeometryKey = nameof(DocumentEmptyGeometryKey),
DocumentPairGeometryKey = nameof(DocumentPairGeometryKey),
DocumentStarGeometryKey = nameof(DocumentStarGeometryKey),
DraggableGeometryKey = nameof(DraggableGeometryKey),
EditDocumentAltGeometryKey = nameof(EditDocumentAltGeometryKey),
EditDocumentGeometryKey = nameof(EditDocumentGeometryKey),
VolCurveGeometryKey = nameof(VolCurveGeometryKey),
FinancialGrowthGeometryKey = nameof(FinancialGrowthGeometryKey),
GearGeometryKey = nameof(GearGeometryKey),
HamburgerMenuGeometryKey = nameof(HamburgerMenuGeometryKey),
HornGeometryKey = nameof(HornGeometryKey),
KeyGeometryKey = nameof(KeyGeometryKey),
LetterAKey = nameof(LetterAKey),
LetterDKey = nameof(LetterDKey),
MenuOrientationGeometryKey = nameof(MenuOrientationGeometryKey),
OrdersGeometryKey = nameof(OrdersGeometryKey),
PauseGeometryKey = nameof(PauseGeometryKey),
PaymentGeometryKey = nameof(PaymentGeometryKey),
PencilGeometryKey = nameof(PencilGeometryKey),
PlayGeometryKey = nameof(PlayGeometryKey),
ProhibitedGeometryKey = nameof(ProhibitedGeometryKey),
RubberStampGeometryKey = nameof(RubberStampGeometryKey),
RecurringScheduleGeometryKey = nameof(RecurringScheduleGeometryKey),
SpeakerGeometryKey = nameof(SpeakerGeometryKey),
StarGeometryKey = nameof(StarGeometryKey),
ToolsGeometryKey = nameof(ToolsGeometryKey),
TrashGeometryKey = nameof(TrashGeometryKey),
UndoCircularGeometryKey = nameof(UndoCircularGeometryKey),
WarningExclamationGeometryKey = nameof(WarningExclamationGeometryKey),
WarningGeometryKey = nameof(WarningGeometryKey);
public static Geometry PlayGeometry => Geometry.Parse(get_geometric_path(PlayGeometryKey).FirstOrDefault() ?? string.Empty);
static readonly Pen _copy_boxes_pen = new Pen(Brushes.Black, HighDpiExtensions.RoundLayoutValue(5)).frozen();
static readonly string base_uri = "pack://application:,,,/Images/Icons/";
private static ResourceDictionary _resources = (ResourceDictionary)Application.LoadComponent(new Uri("/Images/Vector/Icons.xaml", UriKind.RelativeOrAbsolute));
private static Uri uri(string filename) {
return new Uri(base_uri + filename);
}
[Obsolete("Please only add new vector icons using icons.xaml")]
private static ImageSource load_image(string filename) {
return new BitmapImage(uri(filename)).frozen();
}
private static ImageSource load_resource_and_freeze(string resource_name) {
lock (_resources) {
return ((DrawingImage)_resources[resource_name]).frozen();
}
}
#pragma warning disable CS0618 // Type or member is obsolete
public static ImageSource Logo { get { return load_image("logo.ico"); } }
public static ImageSource Admin { get { return load_resource_and_freeze("Admin"); } }
public static ImageSource Analytics { get { return load_resource_and_freeze("Analytics"); } }
public static ImageSource Sheets { get { return load_resource_and_freeze("Sheets"); } }
public static ImageSource Trades { get { return load_resource_and_freeze("Trades"); } }
public static ImageSource Depth { get { return load_resource_and_freeze("Depth"); } }
public static ImageSource Ladder { get { return load_resource_and_freeze("Ladder"); } }
public static ImageSource SheetsRed { get { return load_image("SheetsRed.png"); } }
public static ImageSource SheetsGreen { get { return load_image("SheetsGreen.png"); } }
public static ImageSource Spreads { get { return load_resource_and_freeze("Spreads"); } }
public static ImageSource BlueSpreads { get { return load_image("BlueSpread.ico"); } }
public static ImageSource Reports { get { return load_resource_and_freeze("Reports"); } }
public static ImageSource Risk { get { return load_resource_and_freeze("Risk"); } }
public static ImageSource Eye { get { return load_resource_and_freeze("Eye"); } }
public static ImageSource Coins { get { return load_resource_and_freeze("Coins"); } }
public static ImageSource DataCopy { get { return load_image("DataCopy.ico"); } }
public static ImageSource Refresh { get { return load_image("Refresh.png"); } }
public static ImageSource FavoriteWindow { get { return load_image("FavoriteWindow.png"); } }
public static ImageSource Browser => load_resource_and_freeze("Browser");
public static ImageSource Date { get { return load_image("Date.png"); } }
public static ImageSource Cube3d { get { return load_resource_and_freeze("Cube"); } }
public static ImageSource Algo { get { return Cube3d; } }
public static ImageSource Quote { get { return Math; } }
public static ImageSource Math { get { return load_resource_and_freeze("Surface"); } }
public static ImageSource Abacus { get { return load_image("Abacus.png"); } }
public static ImageSource Delete { get { return load_image("Delete.png"); } }
public static ImageSource Up_Arrow { get { return load_image("Arrowhead-Up.png"); } }
public static ImageSource Down_Arrow { get { return load_image("Arrowhead-Down.png"); } }
public static ImageSource Zoom_In { get { return load_image("Zoom-In.png"); } }
public static ImageSource Zoom_Out { get { return load_image("Zoom-Out.png"); } }
public static ImageSource InsertionArrow { get { return load_image("InsertionArrow.png"); } }
#pragma warning restore CS0618
// Vector icons
public static ImageSource Bookmarks { get { return load_resource_and_freeze("Bookmarks"); } }
public static ImageSource Window { get { return load_resource_and_freeze("Window"); } }
public static ImageSource ActiveWindow { get { return load_resource_and_freeze("ActiveWindow"); } }
public static ImageSource Crucible { get { return load_resource_and_freeze("Crucible"); } }
public static ImageSource Accounting { get { return load_resource_and_freeze("Accounting"); } }
public static ImageSource Add { get { return load_resource_and_freeze("Add"); } }
public static ImageSource AddBoxes => create_icon(AddBoxesGeometryKey);
public static ImageSource AddEncircled { get { return load_resource_and_freeze("AddEncircled"); } }
public static ImageSource AddFile => create_icon(Smashicons.AddFileGeometryKey);
public static ImageSource AttachAlgos => create_icon(AttachAlgosKey);
public static ImageSource Beaker { get { return load_resource_and_freeze("Beaker"); } }
public static ImageSource Book { get { return load_resource_and_freeze("Book"); } }
public static ImageSource Orders => create_icon(OrdersGeometryKey);
public static ImageSource AddOrders { get { return load_resource_and_freeze("AddOrders"); } }
public static ImageSource CancelOrders { get { return load_resource_and_freeze("CancelOrders"); } }
public static ImageSource CancelBuys { get { return load_resource_and_freeze("CancelBuys"); } }
public static ImageSource CancelSells { get { return load_resource_and_freeze("CancelSells"); } }
public static ImageSource CancelSelected { get { return load_resource_and_freeze("CancelSelected"); } }
public static ImageSource LadderCancelOrders { get { return load_resource_and_freeze("LadderCancelOrders"); } }
public static ImageSource LadderCancelBuys { get { return load_resource_and_freeze("LadderCancelBuys"); } }
public static ImageSource LadderCancelSells { get { return load_resource_and_freeze("LadderCancelSells"); } }
public static ImageSource Synthetics { get { return load_resource_and_freeze("Synthetics"); } }
public static ImageSource AddSynthetic { get { return load_resource_and_freeze("AddSynthetic"); } }
public static ImageSource RemoveSynthetic { get { return load_resource_and_freeze("RemoveSynthetic"); } }
public static ImageSource ModifySynthetic { get { return load_resource_and_freeze("ModifySynthetic"); } }
public static ImageSource CloneSynthetic { get { return load_resource_and_freeze("CloneSynthetic"); } }
public static ImageSource analytics => Math;
public static ImageSource ModifyOrder { get { return load_resource_and_freeze("ModifyOrder"); } }
public static ImageSource call_put => create_icon(CallPutGeometryKey);
public static ImageSource call_put_checked =>
create_checked_icon(
CallPutGeometryKey,
brush: Brushes.Black,
check_brush: Brushes.Black,
check_off_x_pct: 0.9);
public static ImageSource call_put_unchecked =>
create_checked_icon(
CallPutGeometryKey,
brush: Brushes.Black,
check_brush: Brushes.Transparent,
check_off_x_pct: 0.9);
public static ImageSource candidate => create_icon(CandidateGeometryKey);
public static ImageSource candidate_unchecked =>
create_checked_icon(CandidateGeometryKey, Brushes.Black, check_brush: Brushes.Transparent);
public static ImageSource candidate_checked =>
create_checked_icon(CandidateGeometryKey, Brushes.Black, check_brush: Brushes.Black);
public static ImageSource candidate_with_audience =>
create_icon(CandidateWithAudienceGeometryKey);
public static ImageSource CheckMark => create_icon(CheckMarkGeometryKey);
public static ImageSource ChevronRight => new DrawingImage(create_chevron_right_drawing());
public static ImageSource ChevronDown => new DrawingImage(create_chevron_down_drawing());
public static ImageSource Clock { get { return load_resource_and_freeze("Clock"); } }
public static ImageSource CopyWF => create_icon(CopyWFGeometryKey);
public static ImageSource CopyBoxes => create_icon(CopyBoxesGeometryKey, null, _copy_boxes_pen);
public static ImageSource CurrencyExchange => create_icon(CurrencyExchangeGeometryKey);
public static ImageSource DataEdit => create_icon(DataEditGeometryKey);
public static ImageSource Defrag { get { return load_resource_and_freeze("Defrag"); } }
public static ImageSource DetachAlgos => create_icon_and_rotate(DetachAlgosKey, Brushes.Red);
public static ImageSource Disk => create_icon(DiskGeometryKey);
public static ImageSource DiskFile => create_icon(DiskFileGeometryKey);
public static ImageSource Display { get { return load_resource_and_freeze("Display"); } }
public static ImageSource DocumentAdd => create_icon(DocumentAddGeometryKey);
public static ImageSource DocumentBroken => create_icon(DocumentBrokenGeometryKey);
public static ImageSource DocumentCopy => create_icon(DocumentCopyGeometryKey);
public static ImageSource DocumentEmpty => create_icon(DocumentEmptyGeometryKey);
public static ImageSource DocumentPair => create_icon(DocumentPairGeometryKey);
public static ImageSource DocumentStar => create_icon(DocumentStarGeometryKey);
public static ImageSource Draggable => create_icon(DraggableGeometryKey);
public static ImageSource EditDocument => create_icon("Smashicons.EditDocument.GeometryKey");
public static ImageSource VolCurve => create_icon(VolCurveGeometryKey);
public static ImageSource Export => load_resource_and_freeze("Export");
public static ImageSource Filter { get { return load_resource_and_freeze("Filter"); } }
public static ImageSource FilterActive { get { return load_resource_and_freeze("FilterActive"); } }
public static ImageSource FilterError { get { return load_resource_and_freeze("FilterError"); } }
public static ImageSource FinancialGrowth => create_icon(FinancialGrowthGeometryKey);
public static ImageSource FinancialGrowthGray => create_icon(FinancialGrowthGeometryKey, Brushes.Gray);
public static ImageSource Gear => create_icon(GearGeometryKey);
public static ImageSource HamburgerMenu => create_icon(HamburgerMenuGeometryKey);
public static ImageSource Horn => create_icon(HornGeometryKey);
public static ImageSource Import => load_resource_and_freeze("Import");
public static ImageSource Key => create_icon(KeyGeometryKey);
public static ImageSource Knight { get { return load_resource_and_freeze("Knight"); } }
public static ImageSource MenuOrientation => create_icon(MenuOrientationGeometryKey);
public static ImageSource options_view => Sheets;
public static ImageSource Pause => create_icon(PauseGeometryKey);
public static ImageSource Payment => create_icon(PaymentGeometryKey);
public static ImageSource Pencil => create_icon(PencilGeometryKey);
public static ImageSource Play => create_icon(PlayGeometryKey);
public static ImageSource Prohibited => create_icon(ProhibitedGeometryKey);
public static ImageSource RecurringSchedule => create_icon(RecurringScheduleGeometryKey);
public static ImageSource RecurringScheduleGray => create_icon(RecurringScheduleGeometryKey, Brushes.Gray);
public static ImageSource RubberStamp => create_icon(RubberStampGeometryKey);
public static ImageSource RedoCircular => create_icon(UndoCircularGeometryKey, Brushes.Black, null, new ScaleTransform(-1, 1));
public static ImageSource Spawn { get { return load_resource_and_freeze("Spawn"); } }
public static ImageSource Speaker => create_icon(SpeakerGeometryKey);
public static ImageSource Star => create_icon(StarGeometryKey);
public static ImageSource Target { get { return load_resource_and_freeze("Target"); } }
public static ImageSource Tetris { get { return load_resource_and_freeze("Tetris"); } }
public static ImageSource Tools => create_icon(ToolsGeometryKey);
public static ImageSource Trash => create_icon(TrashGeometryKey);
public static ImageSource Warning => create_icon(WarningGeometryKey, Brushes.IndianRed);
public static ImageSource WarningExclamation => create_icon(WarningExclamationGeometryKey, Brushes.IndianRed);
public static ImageSource UndoCircular => create_icon(UndoCircularGeometryKey);
public static ImageSource ViewSettings => load_resource_and_freeze("ViewSettings");
public static ImageSource vol_curve_unchecked => create_checked_icon(
VolCurveGeometryKey, Brushes.Black, null, Brushes.Transparent, null, check_off_x_pct: 0.8);
public static ImageSource vol_curve_checked => create_checked_icon(
VolCurveGeometryKey, Brushes.Black, null, Brushes.Black, null, check_off_x_pct: 0.8);
public static ImageSource vol_surface => Math;
public static ImageSource Wrench { get { return load_resource_and_freeze("Wrench"); } }
public static ImageSource RightArrow => create_icon(
ArrowGeometryKey, null, new(BTSColors.UI.icon_foreground, 3));
public static ImageSource DownArrow => create_icon(
ArrowGeometryKey, null, new(BTSColors.UI.icon_foreground, 3), new RotateTransform(90, 0.5, 0.5));
public static ImageSource Factory { get { return (load_resource_and_freeze("Factory")); } }
public static ImageSource DotsVertical { get { return (load_resource_and_freeze("DotsVertical")); } }
public static ImageSource HandPointingOverDocument => load_resource_and_freeze("HandPointingOverDocument");
public static ImageSource Support => load_resource_and_freeze("SupportIcon");
public static ImageSource FloppyDisk => create_icon("FloppyDisk");
static Brush _default_chevron_brush => null;
static Pen _default_chevron_pen { get; } = new Pen(BTSColors.UI.default_text, 3).frozen();
public static ImageSource create_icon(string geometric_path_key) =>
create_icon(geometric_path_key, BTSColors.UI.icon_foreground);
public static ImageSource create_icon(string geometric_path_key, Brush brush, Pen pen = null, Transform transform = null) {
var rv = new DrawingImage(create_drawing(geometric_path_key, brush, pen, transform));
rv.Freeze();
return rv;
}
public static ImageSource create_icon_and_rotate(string geometric_path_key, Brush brush = null, Pen pen = null, Transform transform = null, double degrees = 90) {
if (brush == null) {
brush = Brushes.Black;
}
var drawing = create_drawing(geometric_path_key, brush, pen, transform);
var dg = new DrawingGroup();
dg.Children.Add(drawing);
dg.Transform = new RotateTransform(degrees);
var rv = new DrawingImage(dg);
rv.Freeze();
return rv;
}
public static Drawing create_drawing(string geometric_path_key) =>
create_drawing(geometric_path_key, Brushes.Black);
public static Drawing create_drawing(string geometric_path_key, Brush brush, Pen pen = null, Transform transform = null) =>
create_drawing(get_geometric_path(geometric_path_key), brush, pen, transform);
public static Drawing create_drawing(IEnumerable<string> paths, Brush brush, Pen pen = null, Transform transform = null) {
var drawing_group = new DrawingGroup();
foreach (string p in paths) {
drawing_group.Children.Add(new GeometryDrawing(brush, pen, Geometry.Parse(p)));
}
if (transform != null)
drawing_group.Transform = transform;
return drawing_group;
}
public static IEnumerable<string> get_geometric_path(string 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));
path = string.Empty;
}
return new[] { path };
} else if (obj is string[] paths) {
return paths.Where(p => !string.IsNullOrEmpty(p)).ToArray();
} else return null;
}
public static Drawing create_chevron_right_drawing() =>
create_chevron_right_drawing(_default_chevron_brush, _default_chevron_pen);
public static Drawing create_chevron_right_drawing(Brush brush, Pen pen) {
var drawing_group = new DrawingGroup();
var (left, right) = create_chevron_right_geometry();
drawing_group.Children.Add(new GeometryDrawing(brush, pen, left));
drawing_group.Children.Add(new GeometryDrawing(brush, pen, right));
return drawing_group;
}
public static (Geometry left, Geometry right) create_chevron_right_geometry() {
var arrow_geometry_str = _resources[ArrowGeometryKey] as string ?? throw new InvalidOperationException();
// Must clone bc for some reason Geometry.Parse returns a frozen Geometry
var left = Geometry.Parse(arrow_geometry_str).Clone();
var right = left.Clone();
// bump 2nd arrow to the right
right.Transform = new TranslateTransform(24.0.RoundLayoutValue(), 0);
return (left, right);
}
public static Drawing create_chevron_down_drawing() =>
create_chevron_down_drawing(_default_chevron_brush, _default_chevron_pen);
public static Drawing create_chevron_down_drawing(Brush brush, Pen pen) {
// Transform arrow1 (left -> top), arrow2 (right -> bottom)
var (arrow1, arrow2) = create_chevron_right_geometry();
arrow1.Transform = new RotateTransform(90, 0.5, 0.5);
var arrow2_transform = new TransformGroup();
arrow2_transform.Children.Add(new RotateTransform(90, 0.5, 0.5));
arrow2_transform.Children.Add(new TranslateTransform(0, -24.0.RoundLayoutValue()));
arrow2.Transform = arrow2_transform;
var drawing_group = new DrawingGroup();
drawing_group.Children.Add(new GeometryDrawing(brush, pen, arrow1));
drawing_group.Children.Add(new GeometryDrawing(brush, pen, arrow2));
return drawing_group;
}
public static ImageSource create_checked_icon(string geometric_path_key) =>
create_checked_icon(get_geometric_path(geometric_path_key));
public static ImageSource create_checked_icon(
string geometric_path_key,
Brush brush = null,
Pen pen = null,
Brush check_brush = null,
Pen check_pen = null,
double check_size_ratio = 0.3,
double check_off_x_pct = 1,
double check_off_y_pct = 1) =>
create_checked_icon(
get_geometric_path(geometric_path_key), brush, pen, check_brush, check_pen,
check_size_ratio, check_off_x_pct, check_off_y_pct);
public static ImageSource create_checked_icon(IEnumerable<string> paths) =>
create_checked_icon(paths, Brushes.Black, null);
public static ImageSource create_checked_icon(
IEnumerable<string> paths, Brush brush, Pen pen) =>
create_checked_icon(paths, brush, pen, Brushes.Black, null);
public static ImageSource create_checked_icon(
IEnumerable<string> paths,
Brush brush,
Pen pen,
Brush check_brush,
Pen check_pen,
double check_size_ratio = 0.3,
double check_off_x_pct = 1,
double check_off_y_pct = 1) {
var drawing = create_checked_drawing(
paths, brush,
pen,
check_brush,
check_pen,
check_size_ratio,
check_off_x_pct,
check_off_y_pct);
var rv = new DrawingImage(drawing);
rv.Freeze();
return rv;
}
public static Drawing create_checked_drawing(IEnumerable<string> paths) =>
create_checked_drawing(paths, Brushes.Black, null, Brushes.Black, null);
/// <summary>
/// Create a <see cref="DrawingGroup"/> whose children are a 'main drawing' and a check-mark
/// drawing
/// </summary>
/// <param name="brush">
/// The <see cref="Brush"/> to use for the main <see cref="Drawing"/>
/// </param>
/// <param name="pen">
/// The <see cref="Pen"/> to use for the main <see cref="Drawing"/>
/// </param>
/// <param name="check_brush">
/// The <see cref="Brush"/> to use for the check-mark <see cref="Drawing"/>
/// </param>
/// <param name="check_pen">
/// The <see cref="Pen"/> to use for the check-mark <see cref="Drawing"/>
/// </param>
/// <param name="check_size_ratio">
/// The size ratio of the check-mark and main drawing
/// </param>
/// <param name="check_off_x_pct">
/// The check-mark horizontal offset, defined as a percentage of the main drawing's width
/// </param>
/// <param name="check_off_y_pct">
/// The check-mark vertical offset, defined as a percentage of the main drawing's height
/// </param>
public static DrawingGroup create_checked_drawing(
IEnumerable<string> main_drawing_paths,
Brush brush,
Pen pen,
Brush check_brush,
Pen check_pen,
double check_size_ratio = 0.3,
double check_off_x_pct = 1,
double check_off_y_pct = 1
) {
var main_drawing_group = new DrawingGroup();
main_drawing_group.Children.AddRange(
main_drawing_paths.Select(p => new GeometryDrawing(brush, pen, Geometry.Parse(p))));
var check_geometry = _check_mark_geometry().Clone();
var main_right = main_drawing_group.Bounds.Right;
var main_bottom = main_drawing_group.Bounds.Bottom;
var check_scale = (main_right / check_geometry.Bounds.Width)
.max(main_bottom / check_geometry.Bounds.Height);
var check_net_scale = check_size_ratio * check_scale;
var check_transform = new TransformGroup();
check_transform.Children.AddRange(
new ScaleTransform(check_net_scale, check_net_scale),
new TranslateTransform(main_right * check_off_x_pct, main_bottom * check_off_y_pct));
check_geometry.Transform = check_transform;
main_drawing_group.Children.Add(new GeometryDrawing(check_brush, check_pen, check_geometry));
return main_drawing_group;
}
static Geometry _check_mark_geometry() =>
Geometry.Parse(_resources[CheckMarkGeometryKey] as string ??
throw new InvalidOperationException());
}
}
+133 -62
View File
@@ -166,6 +166,22 @@
</sys:String>
</x:Array>
<!-- Icon by <a href="https://freeicons.io/profile/6156">Reda</a> on <a href="https://freeicons.io">freeicons.io</a> -->
<x:Array x:Key="{x:Static mbts:Icons.RecurringScheduleGeometryKey}" Type="sys:String">
<sys:String>
M69.66,4.05c0-2.23,2.2-4.05,4.94-4.05c2.74,0,4.94,1.81,4.94,4.05v17.72c0,2.23-2.2,4.05-4.94,4.05 c-2.74,0-4.94-1.81-4.94-4.05V4.05L69.66,4.05z M91.37,57.03c4.26,0,8.33,0.85,12.05,2.39c3.87,1.6,7.34,3.94,10.24,6.84 c2.9,2.9,5.24,6.38,6.84,10.23c1.54,3.72,2.39,7.79,2.39,12.05c0,4.26-0.85,8.33-2.39,12.05c-1.6,3.87-3.94,7.34-6.84,10.24 c-2.9,2.9-6.38,5.24-10.23,6.84c-3.72,1.54-7.79,2.39-12.05,2.39c-4.26,0-8.33-0.85-12.05-2.39c-3.87-1.6-7.34-3.94-10.24-6.84 c-2.9-2.9-5.24-6.38-6.84-10.24c-1.54-3.72-2.39-7.79-2.39-12.05c0-4.26,0.85-8.33,2.39-12.05c1.6-3.87,3.94-7.34,6.84-10.24 c2.9-2.9,6.38-5.24,10.23-6.84C83.04,57.88,87.1,57.03,91.37,57.03L91.37,57.03z M89.01,75.37c0-0.76,0.31-1.45,0.81-1.95l0,0l0,0 c0.5-0.5,1.19-0.81,1.96-0.81c0.77,0,1.46,0.31,1.96,0.81c0.5,0.5,0.81,1.19,0.81,1.96v14.74l11.02,6.54l0.09,0.06 c0.61,0.39,1.01,0.98,1.17,1.63c0.17,0.68,0.09,1.42-0.28,2.06l-0.02,0.03c-0.02,0.04-0.04,0.07-0.07,0.1 c-0.39,0.6-0.98,1-1.62,1.16c-0.68,0.17-1.42,0.09-2.06-0.28l-12.32-7.29c-0.43-0.23-0.79-0.58-1.05-0.99 c-0.26-0.42-0.41-0.91-0.41-1.43h0L89.01,75.37L89.01,75.37L89.01,75.37z M109.75,70.16c-2.4-2.4-5.26-4.33-8.43-5.64 c-3.06-1.27-6.42-1.96-9.95-1.96s-6.89,0.7-9.95,1.96c-3.17,1.31-6.03,3.24-8.43,5.64c-2.4,2.4-4.33,5.26-5.64,8.43 c-1.27,3.06-1.96,6.42-1.96,9.95c0,3.53,0.7,6.89,1.96,9.95c1.31,3.17,3.24,6.03,5.64,8.43c2.4,2.4,5.26,4.33,8.43,5.64 c3.06,1.27,6.42,1.96,9.95,1.96s6.89-0.7,9.95-1.96c3.17-1.31,6.03-3.24,8.43-5.64c4.71-4.71,7.61-11.2,7.61-18.38 c0-3.53-0.7-6.89-1.96-9.95C114.08,75.42,112.15,72.56,109.75,70.16L109.75,70.16z M13.45,57.36c-0.28,0-0.53-1.23-0.53-2.74 c0-1.51,0.22-2.73,0.53-2.73h13.48c0.28,0,0.53,1.23,0.53,2.73c0,1.51-0.22,2.74-0.53,2.74H13.45L13.45,57.36z M34.94,57.36 c-0.28,0-0.53-1.23-0.53-2.74c0-1.51,0.22-2.73,0.53-2.73h13.48c0.28,0,0.53,1.23,0.53,2.73c0,1.51-0.22,2.74-0.53,2.74H34.94 L34.94,57.36z M56.43,57.36c-0.28,0-0.53-1.23-0.53-2.74c0-1.51,0.22-2.73,0.53-2.73h13.48c0.28,0,0.53,1.22,0.53,2.72 c-1.35,0.84-2.65,1.76-3.89,2.75H56.43L56.43,57.36z M13.48,73.04c-0.28,0-0.53-1.23-0.53-2.74c0-1.51,0.22-2.74,0.53-2.74h13.48 c0.28,0,0.53,1.23,0.53,2.74c0,1.51-0.22,2.74-0.53,2.74H13.48L13.48,73.04z M34.97,73.04c-0.28,0-0.53-1.23-0.53-2.74 c0-1.51,0.22-2.74,0.53-2.74h13.48c0.28,0,0.53,1.23,0.53,2.74c0,1.51-0.22,2.74-0.53,2.74H34.97L34.97,73.04z M13.51,88.73 c-0.28,0-0.53-1.23-0.53-2.74c0-1.51,0.22-2.74,0.53-2.74h13.48c0.28,0,0.53,1.23,0.53,2.74c0,1.51-0.22,2.74-0.53,2.74H13.51 L13.51,88.73z M35,88.73c-0.28,0-0.53-1.23-0.53-2.74c0-1.51,0.22-2.74,0.53-2.74h13.48c0.28,0,0.53,1.23,0.53,2.74 c0,1.51-0.22,2.74-0.53,2.74H35L35,88.73z M25.29,4.05c0-2.23,2.2-4.05,4.94-4.05c2.74,0,4.94,1.81,4.94,4.05v17.72 c0,2.23-2.21,4.05-4.94,4.05c-2.74,0-4.94-1.81-4.94-4.05V4.05L25.29,4.05z M5.44,38.74h94.08v-20.4c0-0.7-0.28-1.31-0.73-1.76 c-0.45-0.45-1.09-0.73-1.76-0.73h-9.02c-1.51,0-2.74-1.23-2.74-2.74c0-1.51,1.23-2.74,2.74-2.74h9.02c2.21,0,4.19,0.89,5.64,2.34 c1.45,1.45,2.34,3.43,2.34,5.64v32.39c-1.8-0.62-3.65-1.12-5.55-1.49v-5.06h0.06H5.44v52.83c0,0.7,0.28,1.31,0.73,1.76 c0.45,0.45,1.09,0.73,1.76,0.73h44.71c0.51,1.9,1.15,3.75,1.92,5.53H7.98c-2.2,0-4.19-0.89-5.64-2.34C0.89,101.26,0,99.28,0,97.07 V18.36c0-2.2,0.89-4.19,2.34-5.64c1.45-1.45,3.43-2.34,5.64-2.34h9.63c1.51,0,2.74,1.23,2.74,2.74c0,1.51-1.23,2.74-2.74,2.74H7.98 c-0.7,0-1.31,0.28-1.76,0.73c-0.45,0.45-0.73,1.09-0.73,1.76v20.4H5.44L5.44,38.74z M43.07,15.85c-1.51,0-2.74-1.23-2.74-2.74 c0-1.51,1.23-2.74,2.74-2.74h18.36c1.51,0,2.74,1.23,2.74,2.74c0,1.51-1.23,2.74-2.74,2.74H43.07L43.07,15.85z
</sys:String>
</x:Array>
<!-- Icon by <a href="https://freeicons.io/profile/75801">Hilmy Abiyyu Asad</a> on <a href="https://freeicons.io">freeicons.io</a> -->
<x:Array x:Key="{x:Static mbts:Icons.FinancialGrowthGeometryKey}" Type="sys:String">
<sys:String>
M29,25H27V13a2,2,0,0,0-2-2H23a2,2,0,0,0-2,2V25H19V16a2,2,0,0,0-2-2H15a2,2,0,0,0-2,2v9H11V19a2,2,0,0,0-2-2H7a2,2,0,0,0-2,2v6H3a1,1,0,0,0,0,2H29a1,1,0,0,0,0-2ZM7,25V19H9v6Zm8,0V16h2v9Zm8,0V13h2V25Z
</sys:String>
<sys:String>
M5,15a1,1,0,0,0,.346-.062L24.062,8.052l-.241.513a1,1,0,1,0,1.811.849L26.905,6.7a1,1,0,0,0-.481-1.33L23.707,4.094a1,1,0,0,0-.848,1.812l.547.256-18.752,6.9A1,1,0,0,0,5,15Z
</sys:String>
</x:Array>
<!--File (the icon is free to use if we include this information in our credit section)
Source: https://www.flaticon.com/authors/freepik
Ttile: File free icon
@@ -388,6 +404,55 @@
c-84.15,0-153-68.85-153-153h-51c0,112.2,91.8,204,204,204s204-91.8,204-204S360.825,89.25,248.625,89.25z
</sys:String>
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
<x:Array x:Key="{x:Static mbts:Icons.VolCurveGeometryKey}" Type="sys:String">
<sys:String>
M952.6,30.6C893.8,30.6,842.2,49.2,799,86c-36.8,31.3-67,75.1-92.4,133.7c-44.4,102.4-65.7,230.7-86.2,354.7C594.3,731.8,567.3,894.6,500,894.6c-24.3,0-60.5-10.5-94.2-101.6c-26.3-71.2-41.6-166-56.4-257.8C337,457.9,325.2,384.9,307.3,329c-10.5-32.8-22.5-57.5-36.6-75.4c-24.8-31.5-53-38.1-72.4-38.1c-27.9,0-54.2,11.6-76.2,33.6c-17.3,17.3-32.1,40.7-45.4,71.5c-20.1,46.8-36,111.1-47.4,190.9C10.2,644.7,10,775.4,10,780.9h0c0,0.2,0,0.3,0,0.5c0,20.7,16.8,37.4,37.4,37.4c20.7,0,37.4-16.8,37.4-37.4c0-0.5,0-1,0-1.5c0.1-12.6,1.1-136.5,18.6-258.3c10.5-73.2,24.7-131,42.1-171.6c9.6-22.3,29.1-59.6,52.8-59.6c1.7,0,6.2,0,13.7,9.5c8.4,10.7,16.5,28.1,24.2,52c16.2,50.5,27.5,120.8,39.5,195.3c15.3,95.3,31.2,193.8,60.1,271.8c16.7,45.2,36.2,79.2,59.6,103.8c29.4,31,64.7,46.7,104.7,46.7c34.4,0,64.5-13.7,89.5-40.8c19.5-21.2,35.9-50.6,49.9-90c24.2-67.8,39.1-157.3,54.8-252c19.8-119.5,40.3-243.2,81.1-337.2c42.4-97.8,98.4-143.6,176.1-144c0.4,0,0.8,0,1.2,0c20.7,0,37.4-16.7,37.4-37.4C990,47.4,973.3,30.6,952.6,30.6z
</sys:String>
</x:Array>
<x:Array x:Key="{x:Static mbts:Icons.CandidateGeometryKey}" Type="sys:String">
<sys:String>
m350.17 14.219c24.742 0.21484 44.621 20.449 44.402 45.191-0.21484 24.742-20.449 44.625-45.191 44.406-24.742-0.21484-44.625-20.449-44.406-45.191 0.21875-24.746 20.449-44.625 45.195-44.406
</sys:String>
<sys:String>
m235.2 92.961c8.9609 28 30.238 49.84 57.68 59.922 3.3594 1.1211 6.7188 1.6797 10.078 2.8008v54.32h92.961v-54.32c3.3594-1.1211 6.7188-1.6797 10.641-2.8008 27.441-10.078 48.719-31.922 57.68-59.922l10.641-32.48c3.3594-11.199-2.8008-22.961-13.441-26.879-11.199-3.3594-22.961 2.8008-26.879 13.441l-10.641 32.48c-5.0391 15.68-16.801 28-31.922 33.602-7.2812 2.8008-14.559 3.9219-22.398 3.9219h-40.32c-7.8398 0-15.121-1.1211-22.398-3.9219-15.121-5.6016-26.879-17.922-31.922-33.602l-10.641-32.48c-3.3594-11.199-15.68-17.359-26.879-13.441-11.199 3.3594-17.359 15.68-13.441 26.879z
</sys:String>
<sys:String>
m465.92 271.6c3.9219 0 7.2812-3.3594 7.2812-7.2812v-25.762c0-3.9219-3.3594-7.2812-7.2812-7.2812l-231.84 0.003906c-3.9219 0-7.2812 3.3594-7.2812 7.2812v25.762c0 3.9219 3.3594 7.2812 7.2812 7.2812h30.801v60.48c0 3.9219 3.3594 7.2812 7.2812 7.2812h156.8c3.9219 0 7.2812-3.3594 7.2812-7.2812l-0.003907-60.484z
</sys:String>
</x:Array>
<x:Array x:Key="{x:Static mbts:Icons.CandidateWithAudienceGeometryKey}" Type="sys:String">
<sys:String>
m350.17 14.219c24.742 0.21484 44.621 20.449 44.402 45.191-0.21484 24.742-20.449 44.625-45.191 44.406-24.742-0.21484-44.625-20.449-44.406-45.191 0.21875-24.746 20.449-44.625 45.195-44.406
</sys:String>
<sys:String>
m235.2 92.961c8.9609 28 30.238 49.84 57.68 59.922 3.3594 1.1211 6.7188 1.6797 10.078 2.8008v54.32h92.961v-54.32c3.3594-1.1211 6.7188-1.6797 10.641-2.8008 27.441-10.078 48.719-31.922 57.68-59.922l10.641-32.48c3.3594-11.199-2.8008-22.961-13.441-26.879-11.199-3.3594-22.961 2.8008-26.879 13.441l-10.641 32.48c-5.0391 15.68-16.801 28-31.922 33.602-7.2812 2.8008-14.559 3.9219-22.398 3.9219h-40.32c-7.8398 0-15.121-1.1211-22.398-3.9219-15.121-5.6016-26.879-17.922-31.922-33.602l-10.641-32.48c-3.3594-11.199-15.68-17.359-26.879-13.441-11.199 3.3594-17.359 15.68-13.441 26.879z
</sys:String>
<sys:String>
m210.56 468.16h-31.359c-24.641 0-45.359 17.922-48.719 42.559l-3.3594 23.52c-1.1211 6.1602 3.9219 11.762 10.078 11.762h114.24c6.1602 0 11.199-5.6016 10.078-11.762l-3.3594-23.52c-2.7969-24.078-23.516-42.559-47.598-42.559z
</sys:String>
<sys:String>
m239.12 411.6c0 24.43-19.809 44.238-44.242 44.238s-44.238-19.809-44.238-44.238c0-24.434 19.805-44.242 44.238-44.242s44.242 19.809 44.242 44.242
</sys:String>
<sys:String>
m365.68 468.16h-31.359c-24.641 0-45.359 17.922-48.719 42.559l-2.8008 23.52c-1.1211 6.1602 3.9219 11.762 10.078 11.762h114.24c6.1602 0 11.199-5.6016 10.078-11.762l-3.3594-23.52c-2.7969-24.078-23.516-42.559-48.156-42.559z
</sys:String>
<sys:String>
m394.24 411.6c0 24.43-19.805 44.238-44.238 44.238s-44.238-19.809-44.238-44.238c0-24.434 19.805-44.242 44.238-44.242s44.238 19.809 44.238 44.242
</sys:String>
<sys:String>
m569.52 510.72c-3.3594-24.078-24.078-42.559-48.719-42.559h-31.359c-24.641 0-45.359 17.922-48.719 42.559l-3.3594 23.52c-1.1211 6.1602 3.9219 11.762 10.078 11.762h114.24c6.1602 0 11.199-5.6016 10.078-11.762z
</sys:String>
<sys:String>
m549.36 411.6c0 24.43-19.805 44.238-44.238 44.238s-44.242-19.809-44.242-44.238c0-24.434 19.809-44.242 44.242-44.242s44.238 19.809 44.238 44.242
</sys:String>
<sys:String>
m465.92 271.6c3.9219 0 7.2812-3.3594 7.2812-7.2812v-25.762c0-3.9219-3.3594-7.2812-7.2812-7.2812l-231.84 0.003906c-3.9219 0-7.2812 3.3594-7.2812 7.2812v25.762c0 3.9219 3.3594 7.2812 7.2812 7.2812h30.801v60.48c0 3.9219 3.3594 7.2812 7.2812 7.2812h156.8c3.9219 0 7.2812-3.3594 7.2812-7.2812l-0.003907-60.484z
</sys:String>
</x:Array>
<sys:String x:Key="{x:Static mbts:Icons.WarningExclamationGeometryKey}">
M15.998999,17.988002C16.551,17.988002 16.999,18.437009 16.999,18.990018 16.999,19.543027 16.551,19.992034 15.998999,19.992034 15.446999,19.992034 14.998999,19.543027 14.998999,18.990018 14.998999,18.437009 15.446999,17.988002 15.998999,17.988002z
M15.998999,8.0630169C16.552,8.0630169,16.999,8.5110159,16.999,9.0650149L16.999,16.167001C16.999,16.721 16.552,17.168998 15.998999,17.168998 15.446,17.168998 14.998999,16.721 14.998999,16.167001L14.998999,9.0650149C14.998999,8.5110159,15.446,8.0630169,15.998999,8.0630169z
@@ -400,6 +465,12 @@
M15.999513,0C16.50052,-3.8678991E-07,17.001274,0.21826346,17.288297,0.65479128L31.74151,22.585975C32.057495,23.064982 32.084472,23.677966 31.812494,24.184989 31.541494,24.687009 31.02049,24.999999 30.450475,24.999999L1.5480773,24.999999C0.97903845,24.999999 0.45705819,24.687009 0.18703459,24.184989 -0.085979476,23.677966 -0.057963934,23.064982 0.25704309,22.585975L14.709219,0.65479128C14.997247,0.21826346,15.498506,-3.8678991E-07,15.999513,0z
</sys:String>
<x:Array x:Key="{x:Static mbts:Icons.CallPutGeometryKey}" Type="sys:String">
<sys:String>
M 11.736 2.328 L 11.04 4.248 Q 10.296 3.888 9.516 3.672 Q 8.846 3.486 7.972 3.46 A 9.769 9.769 0 0 0 7.68 3.456 A 5.081 5.081 0 0 0 5.783 3.805 A 4.795 4.795 0 0 0 4.932 4.248 A 5.08 5.08 0 0 0 3.404 5.827 A 6.475 6.475 0 0 0 3.024 6.528 Q 2.383 7.9 2.332 9.802 A 12.382 12.382 0 0 0 2.328 10.128 A 10.047 10.047 0 0 0 2.476 11.893 A 7.423 7.423 0 0 0 3.012 13.656 A 6.163 6.163 0 0 0 3.873 15.055 A 5.142 5.142 0 0 0 4.908 16.008 A 4.729 4.729 0 0 0 7.583 16.847 A 5.734 5.734 0 0 0 7.68 16.848 A 8.092 8.092 0 0 0 8.633 16.795 Q 9.227 16.724 9.72 16.56 Q 10.584 16.272 11.4 15.816 L 12.096 17.712 A 9.015 9.015 0 0 1 11.017 18.203 A 11.495 11.495 0 0 1 10.068 18.516 Q 9.002 18.819 7.61 18.839 A 13.78 13.78 0 0 1 7.416 18.84 Q 5.232 18.84 3.552 17.796 A 6.864 6.864 0 0 1 1.182 15.289 A 8.38 8.38 0 0 1 0.936 14.82 A 9.027 9.027 0 0 1 0.192 12.488 Q 0.006 11.464 0 10.299 A 15.082 15.082 0 0 1 0 10.224 Q 0 7.656 0.948 5.676 Q 1.896 3.696 3.636 2.58 A 7.049 7.049 0 0 1 6.679 1.521 A 8.95 8.95 0 0 1 7.704 1.464 A 10.953 10.953 0 0 1 8.918 1.528 A 8.448 8.448 0 0 1 9.888 1.692 A 9.174 9.174 0 0 1 11.682 2.303 A 8.552 8.552 0 0 1 11.736 2.328 Z M 28.296 18.552 L 26.016 18.552 L 26.016 1.8 Q 27 1.68 28.188 1.62 A 48.193 48.193 0 0 1 30.331 1.561 A 53.263 53.263 0 0 1 30.648 1.56 Q 32.736 1.56 34.2 2.22 A 5.906 5.906 0 0 1 35.42 2.947 A 4.65 4.65 0 0 1 36.432 4.032 Q 37.2 5.184 37.2 6.672 A 6.062 6.062 0 0 1 37.03 8.141 A 4.624 4.624 0 0 1 36.312 9.72 A 5.355 5.355 0 0 1 34.5 11.311 A 6.736 6.736 0 0 1 33.84 11.628 A 8.346 8.346 0 0 1 31.899 12.162 A 11.327 11.327 0 0 1 30.168 12.288 A 24.966 24.966 0 0 1 29.08 12.265 A 19.903 19.903 0 0 1 28.296 12.216 L 28.296 18.552 Z M 22.728 0.6 L 15.96 20.256 L 14.184 19.656 L 20.952 0 L 22.728 0.6 Z M 28.296 3.576 L 28.296 10.272 A 11.512 11.512 0 0 0 28.608 10.306 Q 28.747 10.32 28.904 10.332 A 23.1 23.1 0 0 0 29.232 10.356 Q 29.784 10.392 30.456 10.392 Q 32.592 10.392 33.768 9.432 A 3.095 3.095 0 0 0 34.933 7.166 A 4.157 4.157 0 0 0 34.944 6.864 A 3.468 3.468 0 0 0 34.762 5.714 A 2.913 2.913 0 0 0 33.816 4.392 A 3.711 3.711 0 0 0 32.597 3.753 Q 31.742 3.48 30.6 3.48 Q 29.952 3.48 29.376 3.504 Q 28.8 3.528 28.296 3.576 Z
</sys:String>
</x:Array>
<!--
'y' for equilateral triangle of side length x:
(x/2)^2 + Y^2 = x^2
@@ -422,9 +493,9 @@
M0,7.79422863406 L3,12.9903810568 6,7.79422863406 Z
</sys:String>
<Geometry x:Key="arrow_geometry">
<sys:String x:Key="{x:Static mbts:Icons.ArrowGeometryKey}">
F1 M 78.1398,324.18L 52.5865,298.626C 51.6892,297.728 50.3385,297.459 49.1678,297.946C 47.9971,298.43 47.2305,299.574 47.2305,300.843L 60.6385,326.398L 47.2305,351.952C 47.2305,353.223 47.9971,354.364 49.1678,354.848C 49.5558,355.011 49.9638,355.09 50.3678,355.09C 51.1838,355.09 51.9852,354.77 52.5865,354.171L 78.1398,328.616C 78.7238,328.032 79.0598,327.224 79.0598,326.398C 79.0598,325.572 78.7238,324.764 78.1398,324.18 Z
</Geometry>
</sys:String>
<DrawingImage x:Key="Bookmarks">
<DrawingImage.Drawing>
@@ -432,7 +503,7 @@
<DrawingGroup.Children>
<GeometryDrawing Geometry="M1540.22,2082.07L1546.95,2102.78 1568.73,2102.78 1551.11,2115.58 1557.84,2136.29 1540.22,2123.49 1522.6,2136.29 1529.33,2115.58 1511.71,2102.78 1533.49,2102.78 1540.22,2082.07z">
<GeometryDrawing.Pen>
<Pen Thickness="3" Brush="Black" />
<Pen Thickness="3" Brush="{mbts:BTSColor UI.icon_foreground}" />
</GeometryDrawing.Pen>
<GeometryDrawing.Brush>
<SolidColorBrush Color="Transparent" />
@@ -454,7 +525,7 @@ M 52.868601,3.8869994 C51.026201,3.8869996 49.534,5.3791947 49.534,7.2190399 49.
M5.2010002,14.812L5.2010002,43.573997 56.098,43.573997 56.098,14.812z
M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<GeometryDrawing.Pen>
<Pen Thickness="1" Brush="Black" />
<Pen Thickness="1" Brush="{mbts:BTSColor UI.icon_foreground}" />
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
@@ -466,14 +537,14 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="
M 32.868601,3.8869994 C31.026201,3.8869996 29.534,5.3791947 29.534,7.2190399 29.534,9.0588851 31.026201,10.553 32.868601,10.553 34.7085,10.553 36.202,9.0588851 36.202,7.2190399 36.202,5.3791947 34.7085,3.8869996 32.868601,3.8869994z
M 42.868601,3.8869994 C41.026201,3.8869996 39.534,5.3791947 39.534,7.2190399 39.534,9.0588851 41.026201,10.553 42.868601,10.553 44.7085,10.553 46.202,9.0588851 46.202,7.2190399 46.202,5.3791947 44.7085,3.8869996 42.868601,3.8869994z
M 52.868601,3.8869994 C51.026201,3.8869996 49.534,5.3791947 49.534,7.2190399 49.534,9.0588851 51.026201,10.553 52.868601,10.553 54.7085,10.553 56.202,9.0588851 56.202,7.2190399 56.202,5.3791947 54.7085,3.8869996 52.868601,3.8869994z
M5.2010002,14.812L5.2010002,43.573997 56.098,43.573997 56.098,14.812z
M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<GeometryDrawing.Pen>
<Pen Thickness="1" Brush="Black" />
<Pen Thickness="1" Brush="{mbts:BTSColor UI.icon_foreground}" />
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
@@ -485,7 +556,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="F1M-198.67,4280.19C-197.609,4277.78 -197.035,4275.17 -197.035,4272.46 -197.035,4267.33 -199.032,4262.51 -202.665,4258.88 -206.286,4255.25 -211.107,4253.26 -216.235,4253.26 -221.365,4253.26 -226.186,4255.25 -229.811,4258.88 -232.498,4261.57 -234.282,4264.92 -235.032,4268.56L-225.835,4278.86 -252.503,4278.86 -250.373,4251.38 -241.577,4261.22C-240.214,4258.14 -238.303,4255.3 -235.844,4252.85 -230.61,4247.61 -223.644,4244.72 -216.235,4244.72 -208.822,4244.72 -201.861,4247.61 -196.627,4252.85 -191.39,4258.08 -188.503,4265.05 -188.503,4272.46 -188.503,4275.11 -188.894,4277.71 -189.617,4280.19L-198.67,4280.19z">
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="F1M-198.67,4280.19C-197.609,4277.78 -197.035,4275.17 -197.035,4272.46 -197.035,4267.33 -199.032,4262.51 -202.665,4258.88 -206.286,4255.25 -211.107,4253.26 -216.235,4253.26 -221.365,4253.26 -226.186,4255.25 -229.811,4258.88 -232.498,4261.57 -234.282,4264.92 -235.032,4268.56L-225.835,4278.86 -252.503,4278.86 -250.373,4251.38 -241.577,4261.22C-240.214,4258.14 -238.303,4255.3 -235.844,4252.85 -230.61,4247.61 -223.644,4244.72 -216.235,4244.72 -208.822,4244.72 -201.861,4247.61 -196.627,4252.85 -191.39,4258.08 -188.503,4265.05 -188.503,4272.46 -188.503,4275.11 -188.894,4277.71 -189.617,4280.19L-198.67,4280.19z">
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
@@ -496,7 +567,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="m 430.4375 225.625 c -1.92352 0.0276 -3.82501 0.82944 -5.1875 2.1875 L 330.0625 323 288 280.9375 c -1.38915 -1.39371 -3.34472 -2.2056 -5.3125 -2.2056 -1.96778 0 -3.92335 0.81189 -5.3125 2.2056 l -23.9375 23.9375 c -1.3844 1.38804 -2.18997 3.33646 -2.18997 5.29687 0 1.96042 0.80557 3.90884 2.18997 5.29688 l 71.3125 71.3125 c 1.38804 1.3844 3.33646 2.18997 5.29687 2.18997 1.96042 0 3.90884 -0.80557 5.29688 -2.18997 l 4.34375 -4.34375 19.59375 -19.59375 100.5 -100.5 c 1.3844 -1.38804 2.18997 -3.33646 2.18997 -5.29688 0 -1.96041 -0.80557 -3.90883 -2.18997 -5.29687 l -23.9375 -23.9375 c -1.41413 -1.40955 -3.40982 -2.21706 -5.40625 -2.1875 z" />
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="m 430.4375 225.625 c -1.92352 0.0276 -3.82501 0.82944 -5.1875 2.1875 L 330.0625 323 288 280.9375 c -1.38915 -1.39371 -3.34472 -2.2056 -5.3125 -2.2056 -1.96778 0 -3.92335 0.81189 -5.3125 2.2056 l -23.9375 23.9375 c -1.3844 1.38804 -2.18997 3.33646 -2.18997 5.29687 0 1.96042 0.80557 3.90884 2.18997 5.29688 l 71.3125 71.3125 c 1.38804 1.3844 3.33646 2.18997 5.29687 2.18997 1.96042 0 3.90884 -0.80557 5.29688 -2.18997 l 4.34375 -4.34375 19.59375 -19.59375 100.5 -100.5 c 1.3844 -1.38804 2.18997 -3.33646 2.18997 -5.29688 0 -1.96041 -0.80557 -3.90883 -2.18997 -5.29687 l -23.9375 -23.9375 c -1.41413 -1.40955 -3.40982 -2.21706 -5.40625 -2.1875 z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -506,7 +577,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M37.063741,37.405188L33.240929,50.771959 33.345182,50.829412C33.743126,51.061163,34.109612,51.337603,34.437061,51.651468L34.468327,51.682901 44.707291,44.003126 44.641921,43.880777C44.347813,43.295671,44.183001,42.63962,44.183001,41.946699L44.185978,41.833834z M24.591099,31.982382L10.519234,39.24213 10.504738,39.424831C10.479679,39.661278,10.436295,39.892527,10.375957,40.117252L10.337856,40.24584 10.451912,40.307037C10.495525,40.332783,10.538376,40.360497,10.58033,40.390192L26.361021,51.547636 26.448517,51.467699C27.339916,50.69132,28.485014,50.17779,29.750544,50.054647L30.015249,50.035364 34.145618,35.590685 29.192999,32.51112C29.04261,32.417593,28.908485,32.31176,28.79232,32.197899L28.716364,32.117622 28.685419,32.139805C28.132467,32.49791 27.465902,32.706999 26.748449,32.706999 26.030621,32.706999 25.363836,32.49791 24.810755,32.139805z M28.780092,24.040133L28.448082,26.492748 28.685419,26.630915C29.607006,27.227547 30.212999,28.238197 30.212999,29.385599 30.212999,29.614918 30.188759,29.838802 30.142603,30.055031L30.080193,30.287708 30.111809,30.297695C30.268356,30.353413,30.424189,30.42791,30.574446,30.521399L34.837221,33.172018 35.327473,31.457518C35.410911,31.165865,35.525216,30.895145,35.662153,30.652515L35.756067,30.497255 35.710442,30.474535C33.991901,29.570229,32.844,27.933699,32.844,26.065052L32.845716,26.006275z M53.770291,20.119031L44.688253,25.319921 44.720247,25.537884C44.740581,25.711212 44.750998,25.887079 44.750998,26.065052 44.750998,28.912514 42.084275,31.221001 38.797749,31.221001L38.67025,31.218208 38.672958,31.305962C38.671358,31.615515,38.625373,31.944508,38.53014,32.277802L37.755445,34.986586 44.966217,39.470285 44.977812,39.451984C45.814164,38.264851 47.230547,37.483999 48.837201,37.483999 49.078189,37.483999 49.314904,37.501568 49.546028,37.535442L49.656656,37.554392 54.505396,20.597714 54.402527,20.541037C54.290171,20.475618,54.180146,20.40689,54.0726,20.334991z M9.6452522,14.786494L9.5807686,14.857854C9.0475883,15.420187,8.3894768,15.871748,7.6484566,16.172216L7.5149994,16.222663 7.5149994,34.615192 7.5420074,34.625397C8.4930382,35.010883,9.2904701,35.676405,9.8216705,36.51416L9.9140587,36.668142 23.306246,29.758877 23.300888,29.725224C23.289059,29.61356 23.282999,29.500257 23.282999,29.385599 23.282999,27.893976 24.307062,26.633465 25.717823,26.213213L26.001564,26.143343 26.439465,22.908201z M25.594164,6.962996L10.989891,11.757046 10.982574,11.849259C10.963779,12.026639,10.935814,12.201424,10.899147,12.373173L10.896881,12.382581 26.821791,20.083639 28.28179,9.2974239 28.12504,9.2381914C27.074772,8.8124379,26.207533,8.0535914,25.667171,7.0996943z M34.637348,6.8116302L34.599276,6.8923512C33.894737,8.2938632,32.502018,9.3174334,30.841724,9.5606082L30.738474,9.5731842 29.162455,21.21555 33.69524,23.407539 33.705906,23.391473C34.750082,21.903184 36.639784,20.909001 38.797749,20.909001 40.441011,20.909001 41.929324,21.486123 43.006821,22.41919L43.020344,22.431472 51.760321,17.426437 51.737371,17.368303C51.521266,16.762437 51.403998,16.112631 51.403998,15.436536 51.403998,14.921415 51.472072,14.421554 51.600069,13.944759L51.681425,13.670171z M30.077951,0C32.588049,0,34.668222,1.7676992,35.036192,4.0752702L35.064489,4.2886443 52.961684,11.489869 53.021899,11.423252C54.161165,10.222043 55.804663,9.4679997 57.631995,9.4679992 61.070987,9.4680003 63.858998,12.139764 63.858998,15.436536 63.858998,18.733305 61.070987,21.405001 57.631995,21.405001L57.456546,21.40075 52.402265,39.080206 52.428996,39.108406C53.093061,39.879898 53.492,40.868822 53.492,41.946699 53.492,44.410421 51.407745,46.407999 48.837201,46.407999 48.033874,46.407999 47.278115,46.212923 46.618644,45.869505L46.615751,45.867823 35.872695,53.925859 35.950705,54.189234C36.069708,54.632677 36.132998,55.097586 36.132998,55.5767 36.132998,58.641745 33.540598,61.126001 30.342699,61.126001 27.144098,61.126001 24.550999,58.641745 24.550999,55.5767 24.550999,55.193407 24.591516,54.819208 24.668669,54.457815L24.711109,54.281561 8.605793,42.894129C8.5577812,42.860109,8.5120659,42.824305,8.4686737,42.786901L8.4553757,42.77429 8.3729744,42.833338C7.5921974,43.338846 6.6510086,43.634001 5.6380043,43.634001 2.935627,43.634001 0.74499893,41.535135 0.74499893,38.9454 0.74499893,36.841322 2.1911545,35.061296 4.1829567,34.467758L4.2889977,34.438908 4.2889977,16.456114 4.1295319,16.420828C1.7547989,15.835048 0,13.768469 0,11.309781 0,8.3958501 2.4649048,6.0340006 5.5053978,6.0339997 7.5959015,6.0340006 9.4142189,7.1503434 10.346516,8.7949429L10.425873,8.9434187 25.113558,4.1221313 25.119768,4.0752702C25.48749,1.7676992,27.566404,0,30.077951,0z" />
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M37.063741,37.405188L33.240929,50.771959 33.345182,50.829412C33.743126,51.061163,34.109612,51.337603,34.437061,51.651468L34.468327,51.682901 44.707291,44.003126 44.641921,43.880777C44.347813,43.295671,44.183001,42.63962,44.183001,41.946699L44.185978,41.833834z M24.591099,31.982382L10.519234,39.24213 10.504738,39.424831C10.479679,39.661278,10.436295,39.892527,10.375957,40.117252L10.337856,40.24584 10.451912,40.307037C10.495525,40.332783,10.538376,40.360497,10.58033,40.390192L26.361021,51.547636 26.448517,51.467699C27.339916,50.69132,28.485014,50.17779,29.750544,50.054647L30.015249,50.035364 34.145618,35.590685 29.192999,32.51112C29.04261,32.417593,28.908485,32.31176,28.79232,32.197899L28.716364,32.117622 28.685419,32.139805C28.132467,32.49791 27.465902,32.706999 26.748449,32.706999 26.030621,32.706999 25.363836,32.49791 24.810755,32.139805z M28.780092,24.040133L28.448082,26.492748 28.685419,26.630915C29.607006,27.227547 30.212999,28.238197 30.212999,29.385599 30.212999,29.614918 30.188759,29.838802 30.142603,30.055031L30.080193,30.287708 30.111809,30.297695C30.268356,30.353413,30.424189,30.42791,30.574446,30.521399L34.837221,33.172018 35.327473,31.457518C35.410911,31.165865,35.525216,30.895145,35.662153,30.652515L35.756067,30.497255 35.710442,30.474535C33.991901,29.570229,32.844,27.933699,32.844,26.065052L32.845716,26.006275z M53.770291,20.119031L44.688253,25.319921 44.720247,25.537884C44.740581,25.711212 44.750998,25.887079 44.750998,26.065052 44.750998,28.912514 42.084275,31.221001 38.797749,31.221001L38.67025,31.218208 38.672958,31.305962C38.671358,31.615515,38.625373,31.944508,38.53014,32.277802L37.755445,34.986586 44.966217,39.470285 44.977812,39.451984C45.814164,38.264851 47.230547,37.483999 48.837201,37.483999 49.078189,37.483999 49.314904,37.501568 49.546028,37.535442L49.656656,37.554392 54.505396,20.597714 54.402527,20.541037C54.290171,20.475618,54.180146,20.40689,54.0726,20.334991z M9.6452522,14.786494L9.5807686,14.857854C9.0475883,15.420187,8.3894768,15.871748,7.6484566,16.172216L7.5149994,16.222663 7.5149994,34.615192 7.5420074,34.625397C8.4930382,35.010883,9.2904701,35.676405,9.8216705,36.51416L9.9140587,36.668142 23.306246,29.758877 23.300888,29.725224C23.289059,29.61356 23.282999,29.500257 23.282999,29.385599 23.282999,27.893976 24.307062,26.633465 25.717823,26.213213L26.001564,26.143343 26.439465,22.908201z M25.594164,6.962996L10.989891,11.757046 10.982574,11.849259C10.963779,12.026639,10.935814,12.201424,10.899147,12.373173L10.896881,12.382581 26.821791,20.083639 28.28179,9.2974239 28.12504,9.2381914C27.074772,8.8124379,26.207533,8.0535914,25.667171,7.0996943z M34.637348,6.8116302L34.599276,6.8923512C33.894737,8.2938632,32.502018,9.3174334,30.841724,9.5606082L30.738474,9.5731842 29.162455,21.21555 33.69524,23.407539 33.705906,23.391473C34.750082,21.903184 36.639784,20.909001 38.797749,20.909001 40.441011,20.909001 41.929324,21.486123 43.006821,22.41919L43.020344,22.431472 51.760321,17.426437 51.737371,17.368303C51.521266,16.762437 51.403998,16.112631 51.403998,15.436536 51.403998,14.921415 51.472072,14.421554 51.600069,13.944759L51.681425,13.670171z M30.077951,0C32.588049,0,34.668222,1.7676992,35.036192,4.0752702L35.064489,4.2886443 52.961684,11.489869 53.021899,11.423252C54.161165,10.222043 55.804663,9.4679997 57.631995,9.4679992 61.070987,9.4680003 63.858998,12.139764 63.858998,15.436536 63.858998,18.733305 61.070987,21.405001 57.631995,21.405001L57.456546,21.40075 52.402265,39.080206 52.428996,39.108406C53.093061,39.879898 53.492,40.868822 53.492,41.946699 53.492,44.410421 51.407745,46.407999 48.837201,46.407999 48.033874,46.407999 47.278115,46.212923 46.618644,45.869505L46.615751,45.867823 35.872695,53.925859 35.950705,54.189234C36.069708,54.632677 36.132998,55.097586 36.132998,55.5767 36.132998,58.641745 33.540598,61.126001 30.342699,61.126001 27.144098,61.126001 24.550999,58.641745 24.550999,55.5767 24.550999,55.193407 24.591516,54.819208 24.668669,54.457815L24.711109,54.281561 8.605793,42.894129C8.5577812,42.860109,8.5120659,42.824305,8.4686737,42.786901L8.4553757,42.77429 8.3729744,42.833338C7.5921974,43.338846 6.6510086,43.634001 5.6380043,43.634001 2.935627,43.634001 0.74499893,41.535135 0.74499893,38.9454 0.74499893,36.841322 2.1911545,35.061296 4.1829567,34.467758L4.2889977,34.438908 4.2889977,16.456114 4.1295319,16.420828C1.7547989,15.835048 0,13.768469 0,11.309781 0,8.3958501 2.4649048,6.0340006 5.5053978,6.0339997 7.5959015,6.0340006 9.4142189,7.1503434 10.346516,8.7949429L10.425873,8.9434187 25.113558,4.1221313 25.119768,4.0752702C25.48749,1.7676992,27.566404,0,30.077951,0z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -516,7 +587,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M3.3500004,28.921999L16.410999,28.921999 16.410999,29.396999 16.410999,32.959999 16.410999,38.421999 25.514,38.421999 25.514,42.458 25.495,42.458 25.495,47.602999 34.698,47.602999 34.698,51.640999 25.495,51.640999 25.495,51.671 21.458,51.671 21.458,42.458 16.410999,42.458 12.453001,42.458 12.374001,42.458 12.374001,32.959999 3.3500004,32.959999z M54.794001,20.069L59.39695,23.324425 64,26.580851 59.39695,29.837375 54.794001,33.094 54.794001,30.650999 33.583,30.650999 33.583,22.698998 54.794001,22.698998z M14.7162,0.3409996L24.9141,0.3409996C25.97705,0.3409996,26.865667,1.1746159,27.071213,2.1986313L27.086924,2.3030968 27.124624,2.3546333C27.940995,3.4717503 29.881758,6.1571293 30.565413,7.3636971 30.565413,7.3636971 34.096944,13.338465 34.877442,15.061705L34.890623,15.092 40.170837,15.092C41.324416,15.092 42.257998,16.195044 42.257998,17.396999 42.257998,18.600256 41.324416,19.702 40.170837,19.702L33.450961,19.702C32.370606,19.702,31.482553,18.733671,31.375766,17.621177L31.37387,17.581701 29.230907,13.962816 22.261399,18.123934 26.40747,22.377669C27.150276,23.141019,27.230264,24.306093,26.654201,25.155003L26.643522,25.169146 26.636381,25.286112C26.628118,25.36014,26.616044,25.434453,26.600019,25.508835L24.851152,33.574084C24.592043,34.765377 23.418798,35.519273 22.228654,35.261475 21.03861,35.004976 20.280681,33.829283 20.53979,32.64039L22.288656,24.57524 22.309726,24.495231 17.488041,19.548167 17.480572,19.539678 17.253374,19.529043C16.366886,19.445599,15.589428,19.018761,15.078829,18.394262L15.074381,18.388281 12.282196,21.977999 12.216562,21.901865 12.1124,21.994324C11.720974,22.306216,11.1803,22.469,10.5833,22.469L2.1626606,22.469C0.96679688,22.469 0,21.817864 0,20.624998 0,19.428434 0.96679688,18.779999 2.1626606,18.779999L9.5252495,18.779999 9.3850002,18.617311 14.600033,11.548028C14.600033,11.548028,15.127697,11.125361,15.599133,10.798839L15.614553,10.78836 15.604,10.776026 24.149192,5.6036739 23.803184,4.9510002 14.7162,4.9510002C13.500099,4.9510002 12.514999,3.8623199 12.514999,2.6472778 12.514999,1.4298038 13.500099,0.3409996 14.7162,0.3409996z M34.6091,0C36.912666,0 38.780001,1.8671761 38.780001,4.1704998 38.780001,6.4739532 36.912666,8.3409996 34.6091,8.3409996 32.304335,8.3409996 30.437,6.4739532 30.437,4.1704998 30.437,1.8671761 32.304335,0 34.6091,0z" />
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M3.3500004,28.921999L16.410999,28.921999 16.410999,29.396999 16.410999,32.959999 16.410999,38.421999 25.514,38.421999 25.514,42.458 25.495,42.458 25.495,47.602999 34.698,47.602999 34.698,51.640999 25.495,51.640999 25.495,51.671 21.458,51.671 21.458,42.458 16.410999,42.458 12.453001,42.458 12.374001,42.458 12.374001,32.959999 3.3500004,32.959999z M54.794001,20.069L59.39695,23.324425 64,26.580851 59.39695,29.837375 54.794001,33.094 54.794001,30.650999 33.583,30.650999 33.583,22.698998 54.794001,22.698998z M14.7162,0.3409996L24.9141,0.3409996C25.97705,0.3409996,26.865667,1.1746159,27.071213,2.1986313L27.086924,2.3030968 27.124624,2.3546333C27.940995,3.4717503 29.881758,6.1571293 30.565413,7.3636971 30.565413,7.3636971 34.096944,13.338465 34.877442,15.061705L34.890623,15.092 40.170837,15.092C41.324416,15.092 42.257998,16.195044 42.257998,17.396999 42.257998,18.600256 41.324416,19.702 40.170837,19.702L33.450961,19.702C32.370606,19.702,31.482553,18.733671,31.375766,17.621177L31.37387,17.581701 29.230907,13.962816 22.261399,18.123934 26.40747,22.377669C27.150276,23.141019,27.230264,24.306093,26.654201,25.155003L26.643522,25.169146 26.636381,25.286112C26.628118,25.36014,26.616044,25.434453,26.600019,25.508835L24.851152,33.574084C24.592043,34.765377 23.418798,35.519273 22.228654,35.261475 21.03861,35.004976 20.280681,33.829283 20.53979,32.64039L22.288656,24.57524 22.309726,24.495231 17.488041,19.548167 17.480572,19.539678 17.253374,19.529043C16.366886,19.445599,15.589428,19.018761,15.078829,18.394262L15.074381,18.388281 12.282196,21.977999 12.216562,21.901865 12.1124,21.994324C11.720974,22.306216,11.1803,22.469,10.5833,22.469L2.1626606,22.469C0.96679688,22.469 0,21.817864 0,20.624998 0,19.428434 0.96679688,18.779999 2.1626606,18.779999L9.5252495,18.779999 9.3850002,18.617311 14.600033,11.548028C14.600033,11.548028,15.127697,11.125361,15.599133,10.798839L15.614553,10.78836 15.604,10.776026 24.149192,5.6036739 23.803184,4.9510002 14.7162,4.9510002C13.500099,4.9510002 12.514999,3.8623199 12.514999,2.6472778 12.514999,1.4298038 13.500099,0.3409996 14.7162,0.3409996z M34.6091,0C36.912666,0 38.780001,1.8671761 38.780001,4.1704998 38.780001,6.4739532 36.912666,8.3409996 34.6091,8.3409996 32.304335,8.3409996 30.437,6.4739532 30.437,4.1704998 30.437,1.8671761 32.304335,0 34.6091,0z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -526,7 +597,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M55.859353,59.282085C56.00929,59.285538,56.143475,59.392647,56.172002,59.547607L55.789193,65.810493C55.674588,66.466682,55.295579,65.802589,55.295579,65.802589L54.473962,64.431519C51.7422,68.327347 47.221295,70.881996 42.101273,70.881996 36.226228,70.881996 31.13625,67.53186 28.632329,62.638653 28.382323,62.158161 28.059378,61.686871 27.969502,61.146481 27.66084,59.337914 29.858891,59.01112 30.614098,59.864002 30.926646,60.216797 31.299044,60.827484 31.563321,61.306576 33.567227,65.081306 37.533479,67.649055 42.101273,67.649055 46.122369,67.649055 49.669251,65.651596 51.828099,62.602253L50.338567,62.323559C50.338567,62.323559,49.473847,62.210258,50.067658,61.849567L55.794392,59.287113C55.816193,59.283215,55.837933,59.28159,55.859353,59.282085z M40.764077,45.717999L43.468282,45.717999 43.468282,47.945969C44.940877,48.043633,45.939504,48.464172,46.57486,48.781933L46.850839,48.919876 45.9889,51.849625 45.591931,51.649216C44.965676,51.336708 43.994244,50.849598 42.497052,50.849598 41.307038,50.849598 40.589589,51.340611 40.589589,52.155632 40.589589,52.883549 41.269242,53.390064 43.278195,54.159683 46.150391,55.237812 47.377004,56.67535 47.377004,58.964413 47.377004,61.232674 45.806714,62.99192 43.348592,63.516731L43.348592,66.047997 40.616887,66.047997 40.616887,63.706738C39.216088,63.607735,37.791692,63.200325,36.902394,62.633808L36.672002,62.482704 37.5286,59.474827 37.945279,59.724831C38.568932,60.09864 39.856541,60.726257 41.489224,60.726257 42.825127,60.726257 43.684468,60.136341 43.684468,59.230118 43.684468,58.503498 43.274297,57.873283 41.294038,57.157166 39.122395,56.362843 36.898515,55.19091 36.898515,52.516441 36.898515,50.313221 38.372449,48.646427 40.764077,48.112602z M42.010037,40.691002C47.882275,40.691002 52.973134,44.039906 55.477063,48.93552 55.725755,49.413418 56.051247,49.888626 56.139745,50.42767 56.447038,52.237579 54.249299,52.563072 53.493916,51.708893 53.181527,51.354805 52.809136,50.742821 52.546143,50.264954 50.543599,46.492958 46.577512,43.922722 42.010037,43.922722 37.98795,43.922722 34.44249,45.919983 32.28362,48.96946L33.773167,49.248013C33.773167,49.248013,34.636472,49.363979,34.044091,49.72456L28.316394,52.28698C28.141854,52.318275,27.969985,52.199879,27.940001,52.026585L28.322789,45.767639C28.43744,45.104939,28.815036,45.774227,28.815036,45.774227L29.632752,47.140041C32.366937,43.245621,36.88775,40.691002,42.010037,40.691002z M21.804616,0L44.531026,0C48.257512,0,51.280999,3.0222199,51.280999,6.7460904L51.280999,38.274937 50.537671,37.898952C49.215222,37.269638,47.812577,36.778652,46.348977,36.444992L45.879922,36.344151 45.879922,6.7460904C45.879922,6.0039101,45.273122,5.3972201,44.531026,5.3972206L22.158713,5.3972206 21.794215,17.167999C21.794215,17.167999,21.325417,24.9519,12.747249,24.0117L5.3957184,23.8125 5.3957184,57.253899C5.3957189,57.998699,6.0024966,58.602901,6.7473038,58.602901L21.820422,58.602901 21.860354,58.884754C22.115357,60.533066,22.574946,62.114872,23.212727,63.604115L23.393945,64 6.7473038,64C3.0207885,64,2.9307267E-07,60.980499,0,57.253899L0,23.0051 2.6718498,20.1863 2.6743804,20.1094 16.677035,5.3972206 16.637936,5.3972206 12.89565,9.3464394 16.817534,5.1914101 16.872334,5.1914101 16.997233,5.0612788 17.007634,5.0612788z" />
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M55.859353,59.282085C56.00929,59.285538,56.143475,59.392647,56.172002,59.547607L55.789193,65.810493C55.674588,66.466682,55.295579,65.802589,55.295579,65.802589L54.473962,64.431519C51.7422,68.327347 47.221295,70.881996 42.101273,70.881996 36.226228,70.881996 31.13625,67.53186 28.632329,62.638653 28.382323,62.158161 28.059378,61.686871 27.969502,61.146481 27.66084,59.337914 29.858891,59.01112 30.614098,59.864002 30.926646,60.216797 31.299044,60.827484 31.563321,61.306576 33.567227,65.081306 37.533479,67.649055 42.101273,67.649055 46.122369,67.649055 49.669251,65.651596 51.828099,62.602253L50.338567,62.323559C50.338567,62.323559,49.473847,62.210258,50.067658,61.849567L55.794392,59.287113C55.816193,59.283215,55.837933,59.28159,55.859353,59.282085z M40.764077,45.717999L43.468282,45.717999 43.468282,47.945969C44.940877,48.043633,45.939504,48.464172,46.57486,48.781933L46.850839,48.919876 45.9889,51.849625 45.591931,51.649216C44.965676,51.336708 43.994244,50.849598 42.497052,50.849598 41.307038,50.849598 40.589589,51.340611 40.589589,52.155632 40.589589,52.883549 41.269242,53.390064 43.278195,54.159683 46.150391,55.237812 47.377004,56.67535 47.377004,58.964413 47.377004,61.232674 45.806714,62.99192 43.348592,63.516731L43.348592,66.047997 40.616887,66.047997 40.616887,63.706738C39.216088,63.607735,37.791692,63.200325,36.902394,62.633808L36.672002,62.482704 37.5286,59.474827 37.945279,59.724831C38.568932,60.09864 39.856541,60.726257 41.489224,60.726257 42.825127,60.726257 43.684468,60.136341 43.684468,59.230118 43.684468,58.503498 43.274297,57.873283 41.294038,57.157166 39.122395,56.362843 36.898515,55.19091 36.898515,52.516441 36.898515,50.313221 38.372449,48.646427 40.764077,48.112602z M42.010037,40.691002C47.882275,40.691002 52.973134,44.039906 55.477063,48.93552 55.725755,49.413418 56.051247,49.888626 56.139745,50.42767 56.447038,52.237579 54.249299,52.563072 53.493916,51.708893 53.181527,51.354805 52.809136,50.742821 52.546143,50.264954 50.543599,46.492958 46.577512,43.922722 42.010037,43.922722 37.98795,43.922722 34.44249,45.919983 32.28362,48.96946L33.773167,49.248013C33.773167,49.248013,34.636472,49.363979,34.044091,49.72456L28.316394,52.28698C28.141854,52.318275,27.969985,52.199879,27.940001,52.026585L28.322789,45.767639C28.43744,45.104939,28.815036,45.774227,28.815036,45.774227L29.632752,47.140041C32.366937,43.245621,36.88775,40.691002,42.010037,40.691002z M21.804616,0L44.531026,0C48.257512,0,51.280999,3.0222199,51.280999,6.7460904L51.280999,38.274937 50.537671,37.898952C49.215222,37.269638,47.812577,36.778652,46.348977,36.444992L45.879922,36.344151 45.879922,6.7460904C45.879922,6.0039101,45.273122,5.3972201,44.531026,5.3972206L22.158713,5.3972206 21.794215,17.167999C21.794215,17.167999,21.325417,24.9519,12.747249,24.0117L5.3957184,23.8125 5.3957184,57.253899C5.3957189,57.998699,6.0024966,58.602901,6.7473038,58.602901L21.820422,58.602901 21.860354,58.884754C22.115357,60.533066,22.574946,62.114872,23.212727,63.604115L23.393945,64 6.7473038,64C3.0207885,64,2.9307267E-07,60.980499,0,57.253899L0,23.0051 2.6718498,20.1863 2.6743804,20.1094 16.677035,5.3972206 16.637936,5.3972206 12.89565,9.3464394 16.817534,5.1914101 16.872334,5.1914101 16.997233,5.0612788 17.007634,5.0612788z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -536,7 +607,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="F1M70.546875,54.3758316040039L77.484375,54.3758316040039 77.484375,89.0633316040039 70.546875,89.0633316040039 70.546875,54.3758316040039z M48.5625,54.3758316040039L65.90625,71.7195816040039 48.5625,89.0633316040039 48.5625,75.1883316040039 8.109375,75.1883316040039 8.109375,68.2508316040039 48.5625,68.2508316040039 48.5625,54.3758316040039z M37.03125,19.6883316040039L37.03125,33.5633316040039 77.484375,33.5633316040039 77.484375,40.5008316040039 37.03125,40.5008316040039 37.03125,54.3758316040039 19.6875,37.0320816040039 37.03125,19.6883316040039z M8.109375,19.6883316040039L15.046875,19.6883316040039 15.046875,54.3758316040039 8.109375,54.3758316040039 8.109375,19.6883316040039z" />
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="F1M70.546875,54.3758316040039L77.484375,54.3758316040039 77.484375,89.0633316040039 70.546875,89.0633316040039 70.546875,54.3758316040039z M48.5625,54.3758316040039L65.90625,71.7195816040039 48.5625,89.0633316040039 48.5625,75.1883316040039 8.109375,75.1883316040039 8.109375,68.2508316040039 48.5625,68.2508316040039 48.5625,54.3758316040039z M37.03125,19.6883316040039L37.03125,33.5633316040039 77.484375,33.5633316040039 77.484375,40.5008316040039 37.03125,40.5008316040039 37.03125,54.3758316040039 19.6875,37.0320816040039 37.03125,19.6883316040039z M8.109375,19.6883316040039L15.046875,19.6883316040039 15.046875,54.3758316040039 8.109375,54.3758316040039 8.109375,19.6883316040039z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -546,7 +617,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M0,27.006001L37.806999,27.006001 37.806999,31.806 0,31.806z M0,18.003L37.806999,18.003 37.806999,22.806 0,22.806z M0,8.9999999L37.806999,8.9999999 37.806999,13.803 0,13.803z M0,0L37.806999,0 37.806999,4.8030009 0,4.8030009z" />
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M0,27.006001L37.806999,27.006001 37.806999,31.806 0,31.806z M0,18.003L37.806999,18.003 37.806999,22.806 0,22.806z M0,8.9999999L37.806999,8.9999999 37.806999,13.803 0,13.803z M0,0L37.806999,0 37.806999,4.8030009 0,4.8030009z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -556,7 +627,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M -2.7407407 21.999952 V 25 H 11.37037 v -3.000048 z m 0 -4.999952 v 2.999952 H 11.37037 V 17 Z m 0 -5 v 3 H 11.37037 v -3 z m 0 -5 v 3 H 11.37037 V 7 Z m -1 -7 c 0.552 0 1.0810413 0.45297098 1 1 V 5 H 11.37037 V 1 c 0 -0.5529995 0.448 -1 1 -1 0.552 0 1 0.4470005 1 1 0 11.544484 0 19.62158 0 30 0 0.553 -0.448 1 -1 1 -0.552 0 -0.918958 -0.45297 -1 -1 V 27 H -2.7407407 v 4 c 0 0.553 -0.448 1 -1 1 -0.552 0 -1 -0.447 -1 -1 0 -11.54448 0 -19.621581 0 -30 0 -0.5529995 0.448 -1 1 -1 z" />
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M -2.7407407 21.999952 V 25 H 11.37037 v -3.000048 z m 0 -4.999952 v 2.999952 H 11.37037 V 17 Z m 0 -5 v 3 H 11.37037 v -3 z m 0 -5 v 3 H 11.37037 V 7 Z m -1 -7 c 0.552 0 1.0810413 0.45297098 1 1 V 5 H 11.37037 V 1 c 0 -0.5529995 0.448 -1 1 -1 0.552 0 1 0.4470005 1 1 0 11.544484 0 19.62158 0 30 0 0.553 -0.448 1 -1 1 -0.552 0 -0.918958 -0.45297 -1 -1 V 27 H -2.7407407 v 4 c 0 0.553 -0.448 1 -1 1 -0.552 0 -1 -0.447 -1 -1 0 -11.54448 0 -19.621581 0 -30 0 -0.5529995 0.448 -1 1 -1 z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -566,7 +637,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M50.14375,33.389126C50.416863,33.394688,50.653496,33.587773,50.705998,33.864617L50.015995,45.114388C49.810295,46.291462,49.130394,45.097489,49.130394,45.097489L47.65659,42.640538C42.747776,49.635197 34.633152,54.221001 25.433924,54.221001 14.884193,54.221001 5.7437552,48.204125 1.2449617,39.419205 0.80087067,38.552021 0.21358696,37.705738 0.052086769,36.736958 -0.49735315,33.490925 3.4507786,32.901036 4.8049124,34.432404 5.3674143,35.067692 6.034036,36.16407 6.5079177,37.026051 10.106778,43.799416 17.2321,48.413819 25.433924,48.413819 32.656544,48.413819 39.026364,44.826695 42.903977,39.351506L40.229367,38.854115C40.229367,38.854115,38.677464,38.647118,39.742466,37.996033L50.024895,33.398526C50.064972,33.391365,50.104733,33.388333,50.14375,33.389126z M23.030291,9.0310004L27.889918,9.0310004 27.889918,13.028299C30.539786,13.205498,32.324932,13.958096,33.464161,14.528294L33.964176,14.775793 32.417435,20.038878 31.706417,19.68068C30.579987,19.11958 28.839241,18.244583 26.149073,18.244583 24.006916,18.244583 22.723183,19.122181 22.723183,20.590876 22.723183,21.894272 23.943314,22.804369 27.551308,24.187165 32.706444,26.124659 34.911,28.702853 34.911,32.817341 34.911,36.892929 32.090527,40.05172 27.673611,40.989117L27.673611,45.540001 22.767485,45.540001 22.767485,41.330414C20.252919,41.155815,17.695551,40.424118,16.101811,39.404721L15.683999,39.137619 17.221739,33.731438 17.969059,34.180634C19.088988,34.851235 21.402748,35.97873 24.340325,35.97873 26.734886,35.97873 28.276728,34.921635 28.276728,33.291336 28.276728,31.986641 27.547409,30.853846 23.986016,29.57255 20.083815,28.144253 16.095511,26.04406 16.095511,21.239174 16.095511,17.280985 18.737379,14.291395 23.030291,13.329098z M25.268765,0C35.819447,2.7347414E-07 44.961449,6.0155495 49.458798,14.804573 49.902695,15.669173 50.490094,16.516972 50.651287,17.48427 51.198281,20.734265 47.255726,21.318962 45.901341,19.789065 45.336346,19.153567 44.669552,18.051968 44.19566,17.19517 40.5957,10.421881 33.473275,5.8072398 25.268765,5.8072393 18.047545,5.8072398 11.678013,9.3918336 7.8003562,14.867073L10.474627,15.367072C10.474627,15.367072,12.026909,15.574172,10.962921,16.223872L0.67933281,20.826762C0.36037083,20.880062,0.057029126,20.669165,0.00099972012,20.354063L0.69093342,9.1118043C0.89552094,7.9296158,1.5738537,9.124924,1.5738539,9.124924L3.0452772,11.583379C7.9566038,4.584462,16.073666,2.7347414E-07,25.268765,0z" />
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M50.14375,33.389126C50.416863,33.394688,50.653496,33.587773,50.705998,33.864617L50.015995,45.114388C49.810295,46.291462,49.130394,45.097489,49.130394,45.097489L47.65659,42.640538C42.747776,49.635197 34.633152,54.221001 25.433924,54.221001 14.884193,54.221001 5.7437552,48.204125 1.2449617,39.419205 0.80087067,38.552021 0.21358696,37.705738 0.052086769,36.736958 -0.49735315,33.490925 3.4507786,32.901036 4.8049124,34.432404 5.3674143,35.067692 6.034036,36.16407 6.5079177,37.026051 10.106778,43.799416 17.2321,48.413819 25.433924,48.413819 32.656544,48.413819 39.026364,44.826695 42.903977,39.351506L40.229367,38.854115C40.229367,38.854115,38.677464,38.647118,39.742466,37.996033L50.024895,33.398526C50.064972,33.391365,50.104733,33.388333,50.14375,33.389126z M23.030291,9.0310004L27.889918,9.0310004 27.889918,13.028299C30.539786,13.205498,32.324932,13.958096,33.464161,14.528294L33.964176,14.775793 32.417435,20.038878 31.706417,19.68068C30.579987,19.11958 28.839241,18.244583 26.149073,18.244583 24.006916,18.244583 22.723183,19.122181 22.723183,20.590876 22.723183,21.894272 23.943314,22.804369 27.551308,24.187165 32.706444,26.124659 34.911,28.702853 34.911,32.817341 34.911,36.892929 32.090527,40.05172 27.673611,40.989117L27.673611,45.540001 22.767485,45.540001 22.767485,41.330414C20.252919,41.155815,17.695551,40.424118,16.101811,39.404721L15.683999,39.137619 17.221739,33.731438 17.969059,34.180634C19.088988,34.851235 21.402748,35.97873 24.340325,35.97873 26.734886,35.97873 28.276728,34.921635 28.276728,33.291336 28.276728,31.986641 27.547409,30.853846 23.986016,29.57255 20.083815,28.144253 16.095511,26.04406 16.095511,21.239174 16.095511,17.280985 18.737379,14.291395 23.030291,13.329098z M25.268765,0C35.819447,2.7347414E-07 44.961449,6.0155495 49.458798,14.804573 49.902695,15.669173 50.490094,16.516972 50.651287,17.48427 51.198281,20.734265 47.255726,21.318962 45.901341,19.789065 45.336346,19.153567 44.669552,18.051968 44.19566,17.19517 40.5957,10.421881 33.473275,5.8072398 25.268765,5.8072393 18.047545,5.8072398 11.678013,9.3918336 7.8003562,14.867073L10.474627,15.367072C10.474627,15.367072,12.026909,15.574172,10.962921,16.223872L0.67933281,20.826762C0.36037083,20.880062,0.057029126,20.669165,0.00099972012,20.354063L0.69093342,9.1118043C0.89552094,7.9296158,1.5738537,9.124924,1.5738539,9.124924L3.0452772,11.583379C7.9566038,4.584462,16.073666,2.7347414E-07,25.268765,0z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -576,7 +647,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M22.1575,13.53399L21.794301,25.304994C21.794301,25.304994,21.3242,33.088695,12.747401,32.148692L5.3958107,31.949492 5.3958107,65.390895C5.3958107,66.135493,6.0026208,66.7391,6.7473808,66.7391L44.5313,66.7391C45.2734,66.7391,45.8802,66.135493,45.8802,65.390895L45.8802,14.883091C45.8802,14.140891,45.2734,13.53399,44.5313,13.53399z M21.804701,8.1369996L44.5313,8.1369996C48.257802,8.1370001,51.279999,11.15899,51.279999,14.883091L51.279999,65.390895C51.279999,69.117496,48.257802,72.136996,44.5313,72.136996L6.7473808,72.136996C3.0208105,72.136996,5.8073994E-07,69.117496,0,65.390895L0,31.142392 2.6718808,28.322993 2.6745006,28.246392 16.6771,13.53399 16.638001,13.53399 12.8945,17.483192 16.816401,13.328391 16.872401,13.328391 16.9961,13.19799 17.0078,13.19799z M30.352,0L55.255002,0 60.581002,0 60.581002,4.747 60.581002,55.207999 55.255002,55.207999 55.255002,4.747 30.352,4.747z" />
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M22.1575,13.53399L21.794301,25.304994C21.794301,25.304994,21.3242,33.088695,12.747401,32.148692L5.3958107,31.949492 5.3958107,65.390895C5.3958107,66.135493,6.0026208,66.7391,6.7473808,66.7391L44.5313,66.7391C45.2734,66.7391,45.8802,66.135493,45.8802,65.390895L45.8802,14.883091C45.8802,14.140891,45.2734,13.53399,44.5313,13.53399z M21.804701,8.1369996L44.5313,8.1369996C48.257802,8.1370001,51.279999,11.15899,51.279999,14.883091L51.279999,65.390895C51.279999,69.117496,48.257802,72.136996,44.5313,72.136996L6.7473808,72.136996C3.0208105,72.136996,5.8073994E-07,69.117496,0,65.390895L0,31.142392 2.6718808,28.322993 2.6745006,28.246392 16.6771,13.53399 16.638001,13.53399 12.8945,17.483192 16.816401,13.328391 16.872401,13.328391 16.9961,13.19799 17.0078,13.19799z M30.352,0L55.255002,0 60.581002,0 60.581002,4.747 60.581002,55.207999 55.255002,55.207999 55.255002,4.747 30.352,4.747z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -600,7 +671,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M17.9349,52.632801L13.5176,60.285198 22.3529,60.285198z M4.1452103,50.3647L4.1452103,52.622398 59.855499,52.622398 59.855499,50.3647z M17.062819,7.9790001L21.601147,36.012657 25.301687,19.424307 28.011845,37.14275 33.26696,12.41387 36.744106,37.14275 40.357449,27.929331 43.067604,37.14275 46.822746,19.489307 50.89698,37.14275 56.015999,23.676769 56.015999,42.608997 8.1710005,42.608997 8.1710005,23.135174 13.86557,31.999594z M4.1452103,3.8098803L4.1452103,45.6199 59.855499,45.6199 59.855499,3.8098803z M0,0L64,0 64,64 0,64z"/>
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M17.9349,52.632801L13.5176,60.285198 22.3529,60.285198z M4.1452103,50.3647L4.1452103,52.622398 59.855499,52.622398 59.855499,50.3647z M17.062819,7.9790001L21.601147,36.012657 25.301687,19.424307 28.011845,37.14275 33.26696,12.41387 36.744106,37.14275 40.357449,27.929331 43.067604,37.14275 46.822746,19.489307 50.89698,37.14275 56.015999,23.676769 56.015999,42.608997 8.1710005,42.608997 8.1710005,23.135174 13.86557,31.999594z M4.1452103,3.8098803L4.1452103,45.6199 59.855499,45.6199 59.855499,3.8098803z M0,0L64,0 64,64 0,64z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -610,7 +681,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M18.660349,20.393C14.879011,20.393 11.806,23.468643 11.806,27.249899 11.806,31.026154 14.879011,34.103001 18.660349,34.103001 22.444386,34.103001 25.519998,31.026154 25.519998,27.249899 25.519998,23.468643 22.444386,20.393 18.660349,20.393z M50.07317,8.7561953C49.408178,8.7706149 48.735172,8.9156297 48.090648,9.2053407 45.51765,10.359123 44.36155,13.394207 45.51765,15.96858 46.671449,18.541552 49.709146,19.691384 52.283444,18.540251 54.856342,17.378819 56.012442,14.352736 54.856342,11.771862 53.990993,9.8450501 52.068145,8.7129386 50.07317,8.7561953z M15.597473,8.6000007L21.868224,8.6000007 22.20032,14.327933 22.20032,14.531032C23.236712,14.816134,24.218506,15.221134,25.133898,15.736836L25.253695,15.615635 29.675461,11.900828 34.111725,16.338337 30.296556,20.624846 30.165057,20.758946C30.683352,21.674349,31.08955,22.659951,31.378649,23.696451L31.544045,23.696451 37.293999,24.196451 37.293999,30.468565 31.566147,30.803267 31.378649,30.803267C31.08955,31.836972,30.683352,32.821373,30.165057,33.736874L30.280955,33.853974 33.993225,38.274582 29.558261,42.709496 25.271895,38.896988 25.133898,38.758988C24.218506,39.274586,23.236712,39.678185,22.20032,39.963387L22.20032,40.146988 21.868224,45.897 15.597473,45.897 15.093578,40.166485 15.093578,39.959488C14.064985,39.671688,13.084595,39.265385,12.174301,38.749787L12.040102,38.881485 7.7381763,42.709496 3.3033104,38.274582 6.9999428,33.869675 7.1522102,33.721176C6.6379356,32.807072,6.2343292,31.83057,5.9464817,30.803267L5.7499523,30.803267 0,30.468565 0,24.196451 5.7278118,23.696451 5.9464817,23.696451C6.2343292,22.665051,6.6379356,21.687248,7.1522102,20.775946L7.0128822,20.640444 3.1874237,16.338337 7.6209869,11.900828 12.027203,15.600036 12.174301,15.744536C13.084595,15.231535,14.064985,14.825334,15.093578,14.537533L15.093578,14.350033z M52.888157,0L57.259197,1.6601361 56.091211,5.7941664 56.035212,5.937414C56.665401,6.3971274,57.240894,6.9413698,57.753986,7.5533617L57.878984,7.4947021 61.949226,6.0845716 63.865797,10.35405 60.071657,12.331821 59.933659,12.393021C60.053354,13.18731,60.075457,13.977598,60.003952,14.758987L60.12245,14.803286 63.999998,16.682059 62.337223,21.053194 58.253977,19.771912 58.12108,19.721113C57.656389,20.352705,57.112095,20.928097,56.496105,21.441189L56.549604,21.556988 57.962284,25.627228 53.691446,27.541302 51.712375,23.744456 51.653774,23.615557C50.862186,23.736756,50.066597,23.760056,49.285309,23.687157L49.241009,23.800455 47.366036,27.678 42.991099,26.017823 44.277584,21.928082 44.325682,21.799183C43.696789,21.334391,43.121297,20.784899,42.607106,20.171606L42.487208,20.225006 38.469066,21.753483 36.553693,17.486847 40.297138,15.390477 40.441637,15.327978C40.321941,14.53499,40.299839,13.744601,40.372736,12.963413L40.24384,12.915114 36.321998,11.158738 37.984774,6.7851217 42.113513,7.9530752 42.263212,8.009104C42.728206,7.3840535,43.269797,6.8124616,43.879186,6.3033789L43.82189,6.1652506 42.29051,2.1496897 46.562749,0.22918414 48.656518,3.977782 48.722916,4.1289099C49.511906,4.0091622,50.299695,3.9843827,51.075585,4.0534113L51.127785,3.9218233z" />
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M18.660349,20.393C14.879011,20.393 11.806,23.468643 11.806,27.249899 11.806,31.026154 14.879011,34.103001 18.660349,34.103001 22.444386,34.103001 25.519998,31.026154 25.519998,27.249899 25.519998,23.468643 22.444386,20.393 18.660349,20.393z M50.07317,8.7561953C49.408178,8.7706149 48.735172,8.9156297 48.090648,9.2053407 45.51765,10.359123 44.36155,13.394207 45.51765,15.96858 46.671449,18.541552 49.709146,19.691384 52.283444,18.540251 54.856342,17.378819 56.012442,14.352736 54.856342,11.771862 53.990993,9.8450501 52.068145,8.7129386 50.07317,8.7561953z M15.597473,8.6000007L21.868224,8.6000007 22.20032,14.327933 22.20032,14.531032C23.236712,14.816134,24.218506,15.221134,25.133898,15.736836L25.253695,15.615635 29.675461,11.900828 34.111725,16.338337 30.296556,20.624846 30.165057,20.758946C30.683352,21.674349,31.08955,22.659951,31.378649,23.696451L31.544045,23.696451 37.293999,24.196451 37.293999,30.468565 31.566147,30.803267 31.378649,30.803267C31.08955,31.836972,30.683352,32.821373,30.165057,33.736874L30.280955,33.853974 33.993225,38.274582 29.558261,42.709496 25.271895,38.896988 25.133898,38.758988C24.218506,39.274586,23.236712,39.678185,22.20032,39.963387L22.20032,40.146988 21.868224,45.897 15.597473,45.897 15.093578,40.166485 15.093578,39.959488C14.064985,39.671688,13.084595,39.265385,12.174301,38.749787L12.040102,38.881485 7.7381763,42.709496 3.3033104,38.274582 6.9999428,33.869675 7.1522102,33.721176C6.6379356,32.807072,6.2343292,31.83057,5.9464817,30.803267L5.7499523,30.803267 0,30.468565 0,24.196451 5.7278118,23.696451 5.9464817,23.696451C6.2343292,22.665051,6.6379356,21.687248,7.1522102,20.775946L7.0128822,20.640444 3.1874237,16.338337 7.6209869,11.900828 12.027203,15.600036 12.174301,15.744536C13.084595,15.231535,14.064985,14.825334,15.093578,14.537533L15.093578,14.350033z M52.888157,0L57.259197,1.6601361 56.091211,5.7941664 56.035212,5.937414C56.665401,6.3971274,57.240894,6.9413698,57.753986,7.5533617L57.878984,7.4947021 61.949226,6.0845716 63.865797,10.35405 60.071657,12.331821 59.933659,12.393021C60.053354,13.18731,60.075457,13.977598,60.003952,14.758987L60.12245,14.803286 63.999998,16.682059 62.337223,21.053194 58.253977,19.771912 58.12108,19.721113C57.656389,20.352705,57.112095,20.928097,56.496105,21.441189L56.549604,21.556988 57.962284,25.627228 53.691446,27.541302 51.712375,23.744456 51.653774,23.615557C50.862186,23.736756,50.066597,23.760056,49.285309,23.687157L49.241009,23.800455 47.366036,27.678 42.991099,26.017823 44.277584,21.928082 44.325682,21.799183C43.696789,21.334391,43.121297,20.784899,42.607106,20.171606L42.487208,20.225006 38.469066,21.753483 36.553693,17.486847 40.297138,15.390477 40.441637,15.327978C40.321941,14.53499,40.299839,13.744601,40.372736,12.963413L40.24384,12.915114 36.321998,11.158738 37.984774,6.7851217 42.113513,7.9530752 42.263212,8.009104C42.728206,7.3840535,43.269797,6.8124616,43.879186,6.3033789L43.82189,6.1652506 42.29051,2.1496897 46.562749,0.22918414 48.656518,3.977782 48.722916,4.1289099C49.511906,4.0091622,50.299695,3.9843827,51.075585,4.0534113L51.127785,3.9218233z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -620,7 +691,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M33.597977,10.759002C37.946865,10.759002 41.485962,14.285001 41.485962,18.649 41.485962,23 37.946865,26.535 33.597977,26.535 29.23909,26.535 25.709992,23 25.709992,18.649 25.709992,17.784 25.849955,16.953001 26.109888,16.174002 26.779719,16.881001 27.70948,17.327002 28.759213,17.327002 30.778696,17.327002 32.418278,15.691001 32.418278,13.668001 32.418278,12.663001 32.008381,11.748001 31.348551,11.087002 32.058369,10.876001 32.818176,10.759002 33.597977,10.759002z M33.606682,4.3679962C25.92741,4.3679957 19.698065,10.594956 19.698065,18.27293 19.698065,25.953894 25.92741,32.177862 33.606682,32.177862 41.295838,32.177862 47.515175,25.953894 47.515175,18.27293 47.515175,10.594956 41.295838,4.3679957 33.606682,4.3679962z M34.867642,1.546141E-09C36.890393,2.6508449E-05 58.705193,0.41938579 68.893006,18.299923 68.893006,18.299923 57.1442,36.139837 34.44656,34.768854 34.44656,34.768854 14.428583,36.59984 0,18.299923 0,18.299923 9.0791523,0.4590019 34.716553,0.0010111886 34.716553,0.0010114873 34.768162,-1.4442128E-06 34.867642,1.546141E-09z" />
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M33.597977,10.759002C37.946865,10.759002 41.485962,14.285001 41.485962,18.649 41.485962,23 37.946865,26.535 33.597977,26.535 29.23909,26.535 25.709992,23 25.709992,18.649 25.709992,17.784 25.849955,16.953001 26.109888,16.174002 26.779719,16.881001 27.70948,17.327002 28.759213,17.327002 30.778696,17.327002 32.418278,15.691001 32.418278,13.668001 32.418278,12.663001 32.008381,11.748001 31.348551,11.087002 32.058369,10.876001 32.818176,10.759002 33.597977,10.759002z M33.606682,4.3679962C25.92741,4.3679957 19.698065,10.594956 19.698065,18.27293 19.698065,25.953894 25.92741,32.177862 33.606682,32.177862 41.295838,32.177862 47.515175,25.953894 47.515175,18.27293 47.515175,10.594956 41.295838,4.3679957 33.606682,4.3679962z M34.867642,1.546141E-09C36.890393,2.6508449E-05 58.705193,0.41938579 68.893006,18.299923 68.893006,18.299923 57.1442,36.139837 34.44656,34.768854 34.44656,34.768854 14.428583,36.59984 0,18.299923 0,18.299923 9.0791523,0.4590019 34.716553,0.0010111886 34.716553,0.0010114873 34.768162,-1.4442128E-06 34.867642,1.546141E-09z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -630,7 +701,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M3.3390064,47.374004L26.00104,47.374004C26.17504,47.881321 26.361041,48.388939 26.575041,48.889757 27.610043,51.333344 29.086045,53.523722 30.968048,55.406689 31.135048,55.573593 31.309048,55.733997 31.476048,55.894005L3.3390064,55.894005C1.4960022,55.894005,0,54.398552,0,52.555387L0,50.712622C0,48.869556,1.4960022,47.374004,3.3390064,47.374004z M8.6740417,35.422004L25.713049,35.422004C25.220049,37.198282 24.972049,39.03446 24.972049,40.910738 24.972049,41.932125 25.046049,42.947113 25.193049,43.942001L8.6740417,43.942001C6.8310413,43.942001,5.3350391,42.44632,5.3350391,40.60354L5.3350391,38.760464C5.3350391,36.917886,6.8310413,35.422004,8.6740417,35.422004z M44.333998,28.91725L44.333998,31.014374C42.649975,31.25297 41.419993,31.901375 40.634958,32.963784 39.852975,34.026392 39.458993,35.225903 39.458993,36.554114 39.458993,37.565422 39.677987,38.455833 40.118966,39.221838 40.555979,39.98354 41.125986,40.573252 41.829967,40.99555 42.53297,41.425255 43.508984,41.850658 44.758986,42.28466 46.149979,42.776463 47.048965,43.183067 47.451004,43.502871 47.852982,43.819578 48.055986,44.291979 48.055986,44.913282 48.055986,45.51469 47.852982,46.022491 47.451004,46.448399 47.048965,46.874603 46.41597,47.0849 45.560011,47.0849 43.728954,47.0849 42.649975,46.093193 42.325999,44.11248L38.810005,45.030586C39.521005,48.178713,41.360971,49.909225,44.333998,50.214329L44.333998,52.91765 46.607986,52.91765 46.607986,50.202824C48.391985,50.015223 49.755999,49.390217 50.701008,48.33131 51.646992,47.273104 52.118979,45.952789 52.118979,44.36648 52.118979,43.331467 51.888998,42.429262 51.431965,41.65526 50.970966,40.886349 50.360981,40.276442 49.59096,39.839542 48.826006,39.401939 47.763016,38.933239 46.41597,38.440628 45.185011,37.991329 44.384962,37.612823 44.008986,37.307821 43.633984,36.999621 43.446972,36.561912 43.446972,35.991115 43.446972,35.429106 43.641979,34.952402 44.032972,34.558096 44.419996,34.163196 44.935011,33.967896 45.576002,33.967896 46.85701,33.967896 47.797989,34.850602 48.407976,36.612617L51.545002,35.327107C50.795002,32.756988,49.14699,31.319575,46.607986,31.015068L46.607986,28.91725z M3.3390026,23.690004L34.347016,23.690004C33.139015,24.471167 32.010015,25.379241 30.975014,26.414426 29.286014,28.103764 27.917013,30.053523 26.909013,32.203998L3.3390026,32.203998C1.4960022,32.203998,0,30.708376,0,28.865226L0,27.028776C0,25.185925,1.4960022,23.690004,3.3390026,23.690004z M45.470961,22.415C55.686974,22.415 63.96701,30.694868 63.959991,40.924053 63.959991,51.140034 55.680992,59.419998 45.464003,59.419998 41.41096,59.419998 37.659003,58.110893 34.613955,55.900974 31.696961,53.777658 29.412962,50.819633 28.130979,47.380901 27.716977,46.285692 27.408993,45.137482 27.215939,43.948774 27.055966,42.96047 26.96899,41.952459 26.968991,40.917248 26.96899,39.007633 27.255978,37.164823 27.796994,35.428709 28.150998,34.306995 28.597959,33.23199 29.145994,32.210482 31.195984,28.371248 34.553958,25.346428 38.626961,23.723612 40.743967,22.882503 43.053967,22.415 45.470961,22.415z M3.3390045,11.952L38.153052,11.952C39.996056,11.952,41.492057,13.448001,41.492057,15.290001L41.492057,17.133002C41.492057,18.976003,39.996056,20.472003,38.153052,20.472004L3.3390045,20.472004C1.4960022,20.472003,0,18.976003,0,17.133002L0,15.290001C0,13.448001,1.4960022,11.952,3.3390045,11.952z M8.6735134,0L43.487543,0C45.330534,0,46.826027,1.4958782,46.826027,3.3386841L46.826027,5.1814384C46.826027,7.0245428,45.330534,8.5200005,43.487543,8.5200005L8.6735134,8.5200005C6.8304424,8.5200005,5.3350277,7.0245428,5.3350277,5.1814384L5.3350277,3.3386841C5.3350277,1.4958782,6.8304424,0,8.6735134,0z" />
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M3.3390064,47.374004L26.00104,47.374004C26.17504,47.881321 26.361041,48.388939 26.575041,48.889757 27.610043,51.333344 29.086045,53.523722 30.968048,55.406689 31.135048,55.573593 31.309048,55.733997 31.476048,55.894005L3.3390064,55.894005C1.4960022,55.894005,0,54.398552,0,52.555387L0,50.712622C0,48.869556,1.4960022,47.374004,3.3390064,47.374004z M8.6740417,35.422004L25.713049,35.422004C25.220049,37.198282 24.972049,39.03446 24.972049,40.910738 24.972049,41.932125 25.046049,42.947113 25.193049,43.942001L8.6740417,43.942001C6.8310413,43.942001,5.3350391,42.44632,5.3350391,40.60354L5.3350391,38.760464C5.3350391,36.917886,6.8310413,35.422004,8.6740417,35.422004z M44.333998,28.91725L44.333998,31.014374C42.649975,31.25297 41.419993,31.901375 40.634958,32.963784 39.852975,34.026392 39.458993,35.225903 39.458993,36.554114 39.458993,37.565422 39.677987,38.455833 40.118966,39.221838 40.555979,39.98354 41.125986,40.573252 41.829967,40.99555 42.53297,41.425255 43.508984,41.850658 44.758986,42.28466 46.149979,42.776463 47.048965,43.183067 47.451004,43.502871 47.852982,43.819578 48.055986,44.291979 48.055986,44.913282 48.055986,45.51469 47.852982,46.022491 47.451004,46.448399 47.048965,46.874603 46.41597,47.0849 45.560011,47.0849 43.728954,47.0849 42.649975,46.093193 42.325999,44.11248L38.810005,45.030586C39.521005,48.178713,41.360971,49.909225,44.333998,50.214329L44.333998,52.91765 46.607986,52.91765 46.607986,50.202824C48.391985,50.015223 49.755999,49.390217 50.701008,48.33131 51.646992,47.273104 52.118979,45.952789 52.118979,44.36648 52.118979,43.331467 51.888998,42.429262 51.431965,41.65526 50.970966,40.886349 50.360981,40.276442 49.59096,39.839542 48.826006,39.401939 47.763016,38.933239 46.41597,38.440628 45.185011,37.991329 44.384962,37.612823 44.008986,37.307821 43.633984,36.999621 43.446972,36.561912 43.446972,35.991115 43.446972,35.429106 43.641979,34.952402 44.032972,34.558096 44.419996,34.163196 44.935011,33.967896 45.576002,33.967896 46.85701,33.967896 47.797989,34.850602 48.407976,36.612617L51.545002,35.327107C50.795002,32.756988,49.14699,31.319575,46.607986,31.015068L46.607986,28.91725z M3.3390026,23.690004L34.347016,23.690004C33.139015,24.471167 32.010015,25.379241 30.975014,26.414426 29.286014,28.103764 27.917013,30.053523 26.909013,32.203998L3.3390026,32.203998C1.4960022,32.203998,0,30.708376,0,28.865226L0,27.028776C0,25.185925,1.4960022,23.690004,3.3390026,23.690004z M45.470961,22.415C55.686974,22.415 63.96701,30.694868 63.959991,40.924053 63.959991,51.140034 55.680992,59.419998 45.464003,59.419998 41.41096,59.419998 37.659003,58.110893 34.613955,55.900974 31.696961,53.777658 29.412962,50.819633 28.130979,47.380901 27.716977,46.285692 27.408993,45.137482 27.215939,43.948774 27.055966,42.96047 26.96899,41.952459 26.968991,40.917248 26.96899,39.007633 27.255978,37.164823 27.796994,35.428709 28.150998,34.306995 28.597959,33.23199 29.145994,32.210482 31.195984,28.371248 34.553958,25.346428 38.626961,23.723612 40.743967,22.882503 43.053967,22.415 45.470961,22.415z M3.3390045,11.952L38.153052,11.952C39.996056,11.952,41.492057,13.448001,41.492057,15.290001L41.492057,17.133002C41.492057,18.976003,39.996056,20.472003,38.153052,20.472004L3.3390045,20.472004C1.4960022,20.472003,0,18.976003,0,17.133002L0,15.290001C0,13.448001,1.4960022,11.952,3.3390045,11.952z M8.6735134,0L43.487543,0C45.330534,0,46.826027,1.4958782,46.826027,3.3386841L46.826027,5.1814384C46.826027,7.0245428,45.330534,8.5200005,43.487543,8.5200005L8.6735134,8.5200005C6.8304424,8.5200005,5.3350277,7.0245428,5.3350277,5.1814384L5.3350277,3.3386841C5.3350277,1.4958782,6.8304424,0,8.6735134,0z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -640,7 +711,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black"
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M14.200889,0C15.299896,0 16.59991,0.50000046 17.998923,1.4989944 19.597936,2.5990016 20.397944,4.5970043 21.196948,6.4960083 22.495954,9.6950015 23.495961,11.693005 26.093989,11.594006 26.793992,11.594006 27.293996,12.093014 27.293996,12.693005 27.293996,13.393002 26.793992,13.892012 26.193997,13.892012 21.896949,14.092009 20.297938,10.394007 19.097932,7.3960032 18.398921,5.6969966 17.698918,4.0979957 16.699916,3.3979983 15.899907,2.8979978 14.600901,1.9989949 13.700884,2.4989952 12.701883,2.9980039 12.30187,5.0970048 12.20188,6.3960022L13.900898,6.2959961C14.600901,6.2959961,15.100904,6.6960057,15.199904,7.3960032L15.399903,9.6950015C16.799909,10.19401 18.098929,10.894008 19.197938,11.893001 23.995965,15.991012 24.494979,23.287025 20.397944,28.084026 16.099906,32.78203 8.8038569,33.381029 4.0068054,29.184019 -0.79122243,25.086023 -1.3902263,17.79001 2.8067985,12.993009 3.9068136,11.693005 5.405819,10.594005 7.0048309,9.9940128L6.9048391,7.9960098C6.9048391,7.3960032,7.3048363,6.7959966,8.0038471,6.6960057L9.9028645,6.5959992C9.9028645,5.3970083 10.302861,1.6989915 12.701883,0.50000046 13.10188,0.099990942 13.700884,0 14.200889,0z" />
</DrawingGroup.Children>
</DrawingGroup>
@@ -651,7 +722,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M10.659519,13.581999C10.787763,13.581999 10.916255,13.630751 11.01375,13.728755 11.207739,13.924762 11.207739,14.241775 11.01175,14.435782L8.5898266,16.850518 11.012901,19.265967C11.20889,19.460974 11.20889,19.776986 11.013901,19.972994 10.916906,20.070997 10.787913,20.119999 10.65992,20.119999 10.531927,20.119999 10.403934,20.070997 10.30694,19.973994L7.8819971,17.556247 5.4570541,19.973994C5.3600597,20.070997 5.2320671,20.119999 5.1040735,20.119999 4.9760809,20.119999 4.8470879,20.070997 4.7500935,19.972994 4.5551033,19.776986 4.5551033,19.460974 4.7510929,19.265967L7.1741672,16.850518 4.752244,14.435782C4.5562544,14.241775 4.5562544,13.924762 4.7502441,13.728755 4.9452333,13.532748 5.2642155,13.533748 5.4572048,13.727755L7.8819966,16.144916 10.306789,13.727755C10.403284,13.630751,10.531276,13.582,10.659519,13.581999z M7.7229891,10.151996C4.0159941,10.151996 0.99999809,13.156997 0.99999809,16.850998 0.99999809,20.544999 4.0159941,23.55 7.7229891,23.55 10.503235,23.55 12.895357,21.859687 13.917652,19.456124L14.034025,19.162648 14.034025,18.772999 14.164453,18.772999 14.191419,18.682897C14.357855,18.100457 14.44698,17.485905 14.44698,16.850998 14.44698,13.156997 11.429984,10.151996 7.7229891,10.151996z M28.477001,10.135L31.999016,13.663 28.424001,17.244999 27.716998,16.538999 29.693872,14.558 21.322995,14.558 21.322995,13.558 30.482195,13.558 27.769998,10.841z M7.4592972,5.1720018L15.45899,8.869 22.849004,5.1720018z M4.6849804,4.1720018L25.465012,4.1720018 25.465012,10.408002 24.465011,10.408002 24.465011,5.4821377 15.476991,9.9780006 5.6849813,5.4540205 5.6849813,9.4246554 5.7953281,9.3948154C6.4117265,9.2363219 7.0576777,9.1519957 7.7229891,9.1519957 11.981983,9.1519957 15.446978,12.605997 15.446978,16.850998 15.446978,17.514279 15.362384,18.158249 15.203383,18.772749L24.465023,18.772999 24.465023,16.665997 25.465026,16.665997 25.465026,19.772997 14.868521,19.772997 14.839026,19.844827C13.664856,22.607125 10.917235,24.550001 7.7229891,24.550001 3.4649954,24.550001 0,21.095999 0,16.850998 0,13.733575 1.8686953,11.042744 4.5478315,9.8331947L4.6849804,9.7732801z M7.8089724,0L29.631012,0 29.631012,7.2790012 28.63101,7.2790012 28.63101,1 8.8089738,1 8.8089738,3.1080008 7.8089724,3.1080008z" />
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M10.659519,13.581999C10.787763,13.581999 10.916255,13.630751 11.01375,13.728755 11.207739,13.924762 11.207739,14.241775 11.01175,14.435782L8.5898266,16.850518 11.012901,19.265967C11.20889,19.460974 11.20889,19.776986 11.013901,19.972994 10.916906,20.070997 10.787913,20.119999 10.65992,20.119999 10.531927,20.119999 10.403934,20.070997 10.30694,19.973994L7.8819971,17.556247 5.4570541,19.973994C5.3600597,20.070997 5.2320671,20.119999 5.1040735,20.119999 4.9760809,20.119999 4.8470879,20.070997 4.7500935,19.972994 4.5551033,19.776986 4.5551033,19.460974 4.7510929,19.265967L7.1741672,16.850518 4.752244,14.435782C4.5562544,14.241775 4.5562544,13.924762 4.7502441,13.728755 4.9452333,13.532748 5.2642155,13.533748 5.4572048,13.727755L7.8819966,16.144916 10.306789,13.727755C10.403284,13.630751,10.531276,13.582,10.659519,13.581999z M7.7229891,10.151996C4.0159941,10.151996 0.99999809,13.156997 0.99999809,16.850998 0.99999809,20.544999 4.0159941,23.55 7.7229891,23.55 10.503235,23.55 12.895357,21.859687 13.917652,19.456124L14.034025,19.162648 14.034025,18.772999 14.164453,18.772999 14.191419,18.682897C14.357855,18.100457 14.44698,17.485905 14.44698,16.850998 14.44698,13.156997 11.429984,10.151996 7.7229891,10.151996z M28.477001,10.135L31.999016,13.663 28.424001,17.244999 27.716998,16.538999 29.693872,14.558 21.322995,14.558 21.322995,13.558 30.482195,13.558 27.769998,10.841z M7.4592972,5.1720018L15.45899,8.869 22.849004,5.1720018z M4.6849804,4.1720018L25.465012,4.1720018 25.465012,10.408002 24.465011,10.408002 24.465011,5.4821377 15.476991,9.9780006 5.6849813,5.4540205 5.6849813,9.4246554 5.7953281,9.3948154C6.4117265,9.2363219 7.0576777,9.1519957 7.7229891,9.1519957 11.981983,9.1519957 15.446978,12.605997 15.446978,16.850998 15.446978,17.514279 15.362384,18.158249 15.203383,18.772749L24.465023,18.772999 24.465023,16.665997 25.465026,16.665997 25.465026,19.772997 14.868521,19.772997 14.839026,19.844827C13.664856,22.607125 10.917235,24.550001 7.7229891,24.550001 3.4649954,24.550001 0,21.095999 0,16.850998 0,13.733575 1.8686953,11.042744 4.5478315,9.8331947L4.6849804,9.7732801z M7.8089724,0L29.631012,0 29.631012,7.2790012 28.63101,7.2790012 28.63101,1 8.8089738,1 8.8089738,3.1080008 7.8089724,3.1080008z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -661,7 +732,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M2,2L2,25 30,25 30,2z M1,0L31,0C31.552002,0,32,0.44702148,32,1L32,26C32,26.552979,31.552002,27,31,27L17,27 17,30 25,30 25,32 7,32 7,30 15,30 15,27 1,27C0.44799805,27,0,26.552979,0,26L0,1C0,0.44702148,0.44799805,0,1,0z" />
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M2,2L2,25 30,25 30,2z M1,0L31,0C31.552002,0,32,0.44702148,32,1L32,26C32,26.552979,31.552002,27,31,27L17,27 17,30 25,30 25,32 7,32 7,30 15,30 15,27 1,27C0.44799805,27,0,26.552979,0,26L0,1C0,0.44702148,0.44799805,0,1,0z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -671,7 +742,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M16.2,11.1C19,11.1 21.2,13.3 21.2,16.1 21.2,18.9 19,21.1 16.2,21.1 13.4,21.1 11.2,18.9 11.2,16.1 11.2,13.4 13.4,11.1 16.2,11.1z M16.2,6C10.6,6 6,10.6 6,16.1 6,21.7 10.5,26.2 16.1,26.2 21.7,26.2 26.2,21.7 26.2,16.1 26.3,10.6 21.7,6 16.2,6z M15.3,0L16.8,0 16.8,5.1999998C22.2,5.5,26.6,9.6999998,27.1,15L32,15 32,16.5 27.1,16.5 27.1,16.7C26.8,22.3,22.3,26.8,16.7,27.1L16.7,32 15.2,32 15.2,27.1 15.5,27.1 16,27.1C10.2,27,5.5,22.5,5.1999998,16.7L5.1999998,16.5 5.1999998,16.4 0,16.4 0,15 5.3000002,15C5.9000001,9.6999998,10.3,5.5,15.7,5.1999998L15.6,5.1999998 15.3,5.1999998z" />
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M16.2,11.1C19,11.1 21.2,13.3 21.2,16.1 21.2,18.9 19,21.1 16.2,21.1 13.4,21.1 11.2,18.9 11.2,16.1 11.2,13.4 13.4,11.1 16.2,11.1z M16.2,6C10.6,6 6,10.6 6,16.1 6,21.7 10.5,26.2 16.1,26.2 21.7,26.2 26.2,21.7 26.2,16.1 26.3,10.6 21.7,6 16.2,6z M15.3,0L16.8,0 16.8,5.1999998C22.2,5.5,26.6,9.6999998,27.1,15L32,15 32,16.5 27.1,16.5 27.1,16.7C26.8,22.3,22.3,26.8,16.7,27.1L16.7,32 15.2,32 15.2,27.1 15.5,27.1 16,27.1C10.2,27,5.5,22.5,5.1999998,16.7L5.1999998,16.5 5.1999998,16.4 0,16.4 0,15 5.3000002,15C5.9000001,9.6999998,10.3,5.5,15.7,5.1999998L15.6,5.1999998 15.3,5.1999998z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -681,7 +752,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M5.5803752,0C7.1813383,0 8.8833761,0.6000061 10.084373,1.8009948 11.785374,3.5029907 12.285377,5.8049927 11.685397,7.9060059L24.094478,20.31601C26.096505,19.714996 28.398524,20.216003 30.099524,21.916992 31.500535,23.317993 32.101552,25.320007 31.901538,27.121002L28.998504,24.118988C27.69753,22.817993 25.496465,22.817993 24.094478,24.118988 22.693467,25.519989 22.693467,27.622009 24.094478,29.02301L26.997514,31.924988C25.195498,32.225006 23.194447,31.625 21.793437,30.123993 20.191436,28.522003 19.591456,26.119995 20.191436,24.118988L7.7823553,11.709015C5.6803512,12.309998 3.3783338,11.80899 1.6773333,10.108002 0.37629925,8.7070007 -0.224718,6.8049927 0.076309212,5.0039978L2.978307,7.9060059C4.2793407,9.2070007 6.4813823,9.2070007 7.8823928,7.9060059 9.2834034,6.605011 9.2834034,4.4030151 7.8823928,3.0020142L4.9803342,0.10000607C5.1803479,0,5.3803615,0,5.5803752,0z" />
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M5.5803752,0C7.1813383,0 8.8833761,0.6000061 10.084373,1.8009948 11.785374,3.5029907 12.285377,5.8049927 11.685397,7.9060059L24.094478,20.31601C26.096505,19.714996 28.398524,20.216003 30.099524,21.916992 31.500535,23.317993 32.101552,25.320007 31.901538,27.121002L28.998504,24.118988C27.69753,22.817993 25.496465,22.817993 24.094478,24.118988 22.693467,25.519989 22.693467,27.622009 24.094478,29.02301L26.997514,31.924988C25.195498,32.225006 23.194447,31.625 21.793437,30.123993 20.191436,28.522003 19.591456,26.119995 20.191436,24.118988L7.7823553,11.709015C5.6803512,12.309998 3.3783338,11.80899 1.6773333,10.108002 0.37629925,8.7070007 -0.224718,6.8049927 0.076309212,5.0039978L2.978307,7.9060059C4.2793407,9.2070007 6.4813823,9.2070007 7.8823928,7.9060059 9.2834034,6.605011 9.2834034,4.4030151 7.8823928,3.0020142L4.9803342,0.10000607C5.1803479,0,5.3803615,0,5.5803752,0z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -691,7 +762,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M25.700012,16.000016L28.800019,16.000016 28.800019,17.099989 25.700012,17.099989z M23.200012,8.599998L17.200012,16.300004C17.200012,16.500016,17.100006,16.800002,17,17.000014L20.100006,22.50001 15.700012,17.699965C15,17.599989 14.5,17.000014 14.5,16.300004 14.5,15.599991 15,15.000017 15.700012,14.89998L15.800019,14.89998z M15.700012,2.9999971C8.7000124,3.2000091,3.0000002,9.0000224,3,16.000016L6.1000063,16.000016 6.1000063,17.099989 3.1000061,17.099989 3.1000061,17.300002C3.7000124,23.699959,9.1000063,28.79999,15.700012,29.000002L15.800019,29.000002 15.800019,26.000006 16.900025,26.000006 16.900025,29.000002 17.100006,29.000002C23.800019,28.500004 29.100006,22.899971 29.100006,16.099991 29.100006,9.3000092 23.800019,3.7000086 17.100006,3.2000089L16.900025,3.2000089 16.900025,6.2000065 15.800019,6.2000065 15.800019,2.9999971z M16,0C24.800019,0 32,7.2000055 32,16.000016 32,24.799994 24.800019,32 16,32 7.2000124,32 2.3106986E-07,24.799994 0,16.000016 2.3106986E-07,7.2000055 7.2000124,0 16,0z"/>
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M25.700012,16.000016L28.800019,16.000016 28.800019,17.099989 25.700012,17.099989z M23.200012,8.599998L17.200012,16.300004C17.200012,16.500016,17.100006,16.800002,17,17.000014L20.100006,22.50001 15.700012,17.699965C15,17.599989 14.5,17.000014 14.5,16.300004 14.5,15.599991 15,15.000017 15.700012,14.89998L15.800019,14.89998z M15.700012,2.9999971C8.7000124,3.2000091,3.0000002,9.0000224,3,16.000016L6.1000063,16.000016 6.1000063,17.099989 3.1000061,17.099989 3.1000061,17.300002C3.7000124,23.699959,9.1000063,28.79999,15.700012,29.000002L15.800019,29.000002 15.800019,26.000006 16.900025,26.000006 16.900025,29.000002 17.100006,29.000002C23.800019,28.500004 29.100006,22.899971 29.100006,16.099991 29.100006,9.3000092 23.800019,3.7000086 17.100006,3.2000089L16.900025,3.2000089 16.900025,6.2000065 15.800019,6.2000065 15.800019,2.9999971z M16,0C24.800019,0 32,7.2000055 32,16.000016 32,24.799994 24.800019,32 16,32 7.2000124,32 2.3106986E-07,24.799994 0,16.000016 2.3106986E-07,7.2000055 7.2000124,0 16,0z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -701,7 +772,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M7,26L19,26 19,28 7,28z M12.732999,14.533003L13.867999,14.533003 13.867999,15.486002C14.643999,15.519002,15.164999,15.671002,15.546999,15.844003L15.210999,17.068001C14.909999,16.949001 14.376999,16.700003 13.543999,16.700003 12.790999,16.700003 12.547999,17.003002 12.547999,17.307001 12.547999,17.664001 12.952999,17.892002 13.936999,18.238001 15.315999,18.693001 15.870998,19.289001 15.870998,20.264 15.870998,21.228001 15.141998,22.052 13.809999,22.268999L13.809999,23.372999 12.674999,23.372999 12.674999,22.344C11.898999,22.310999,11.146,22.116999,10.705999,21.878L11.052999,20.610001C11.539999,20.860001 12.223,21.087999 12.975999,21.087999 13.635999,21.087999 14.087999,20.85 14.087999,20.416 14.087999,20.004 13.716999,19.744001 12.859999,19.474001 11.620999,19.083 10.775999,18.542002 10.775999,17.490002 10.775999,16.537003 11.492999,15.790002 12.732999,15.562002z M2,12L2,30 24,30 24,12z M2,7L2,10 24,10 24,7z M2,2L2,5 24,5 24,2z M0,0L26,0 26,32 0,32z"/>
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M7,26L19,26 19,28 7,28z M12.732999,14.533003L13.867999,14.533003 13.867999,15.486002C14.643999,15.519002,15.164999,15.671002,15.546999,15.844003L15.210999,17.068001C14.909999,16.949001 14.376999,16.700003 13.543999,16.700003 12.790999,16.700003 12.547999,17.003002 12.547999,17.307001 12.547999,17.664001 12.952999,17.892002 13.936999,18.238001 15.315999,18.693001 15.870998,19.289001 15.870998,20.264 15.870998,21.228001 15.141998,22.052 13.809999,22.268999L13.809999,23.372999 12.674999,23.372999 12.674999,22.344C11.898999,22.310999,11.146,22.116999,10.705999,21.878L11.052999,20.610001C11.539999,20.860001 12.223,21.087999 12.975999,21.087999 13.635999,21.087999 14.087999,20.85 14.087999,20.416 14.087999,20.004 13.716999,19.744001 12.859999,19.474001 11.620999,19.083 10.775999,18.542002 10.775999,17.490002 10.775999,16.537003 11.492999,15.790002 12.732999,15.562002z M2,12L2,30 24,30 24,12z M2,7L2,10 24,10 24,7z M2,2L2,5 24,5 24,2z M0,0L26,0 26,32 0,32z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -711,7 +782,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M12.099998,0L19.799995,0 19.799995,12.1 32,12.1 32,19.799996 19.900002,19.799996 19.900002,31.999999 12.199997,31.999999 12.199997,19.900003 0,19.900003 0,12.199999 12.099998,12.199999z"/>
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M12.099998,0L19.799995,0 19.799995,12.1 32,12.1 32,19.799996 19.900002,19.799996 19.900002,31.999999 12.199997,31.999999 12.199997,19.900003 0,19.900003 0,12.199999 12.099998,12.199999z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -723,7 +794,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup.Children>
<GeometryDrawing Brush="Transparent" Geometry="M14.100037,6L14.100037,14.099998 6,14.099998 6,18 14.100037,18 14.100037,26.099998 18,26.099998 18,18 26,18 26,14.099998 17.900024,14.099998 17.900024,6z M16,0C24.800049,0 32,7.1999969 32,16 32,24.800003 24.800049,32 16,32 7.2000122,32 0,24.800003 0,16 0,7.1999969 7.2000122,0 16,0z">
<GeometryDrawing.Pen>
<Pen Thickness="2" Brush="Black"/>
<Pen Thickness="2" Brush="{mbts:BTSColor UI.icon_foreground}"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
@@ -735,7 +806,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M454.352,398.431L331,190.879V87.42c17.459-6.192,30-22.865,30-42.42c0-24.813-20.187-45-45-45H196
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M454.352,398.431L331,190.879V87.42c17.459-6.192,30-22.865,30-42.42c0-24.813-20.187-45-45-45H196
c-24.813,0-45,20.187-45,45c0,19.555,12.541,36.228,30,42.42v103.459L57.659,398.413c-14.085,23.476-14.442,51.715-0.953,75.539
C70.196,497.776,94.594,512,121.972,512h268.055c27.378,0,51.776-14.224,65.266-38.048
C468.779,450.134,468.427,421.903,454.352,398.431z M196,30h120c8.271,0,15,6.729,15,15s-6.729,15-15,15H196
@@ -758,7 +829,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup.Children>
<GeometryDrawing Brush="Transparent" Geometry="M16.378574,2.0941912E-05C17.053625,-0.0029775997,17.669592,0.31702943,17.669592,0.31702964L27.747614,10.181254C30.078613,11.977292,28.301632,12.163302,28.301632,12.163302L14.005584,15.500376C11.924586,18.496447,15.130586,19.519465,15.130586,19.519465L30.870606,16.081391C32.66065,16.035383,31.786623,17.428421,31.786623,17.428421L15.130586,21.214503C12.353603,22.20553,10.869592,20.092476,10.869592,20.092476L0.76355401,8.8182232C-1.4574583,4.6071207,1.8735417,3.616101,1.8735417,3.616101L16.08762,0.023016395C16.184605,0.0080166093,16.282566,2.082104E-05,16.378574,2.0941912E-05z">
<GeometryDrawing.Pen>
<Pen Brush="Black" Thickness="2"/>
<Pen Brush="{mbts:BTSColor UI.icon_foreground}" Thickness="2"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
@@ -770,7 +841,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M26.84801,26.411987L31.841998,26.411987 31.841998,31.915009 26.84801,31.915009z M10.497003,26.411987L18.709003,26.411987 18.709003,31.915009 10.497003,31.915009z M20.052005,18.708984L25.386005,18.708984 25.386005,31.915009 20.052005,31.915009z M10.497003,14.221985L18.709003,14.221985 18.709003,25.057983 10.497003,25.057983z M20.052005,9.5660095L25.386005,9.5660095 25.386005,17.18399 20.052005,17.18399z M26.84801,7.07901L31.841998,7.07901 31.841998,25.057983 26.84801,25.057983z M10.497003,1.9949951L18.709003,1.9949951 18.709003,12.686005 10.497003,12.686005z M0,0L9.2280055,0 9.2280055,32 0,32z"/>
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M26.84801,26.411987L31.841998,26.411987 31.841998,31.915009 26.84801,31.915009z M10.497003,26.411987L18.709003,26.411987 18.709003,31.915009 10.497003,31.915009z M20.052005,18.708984L25.386005,18.708984 25.386005,31.915009 20.052005,31.915009z M10.497003,14.221985L18.709003,14.221985 18.709003,25.057983 10.497003,25.057983z M20.052005,9.5660095L25.386005,9.5660095 25.386005,17.18399 20.052005,17.18399z M26.84801,7.07901L31.841998,7.07901 31.841998,25.057983 26.84801,25.057983z M10.497003,1.9949951L18.709003,1.9949951 18.709003,12.686005 10.497003,12.686005z M0,0L9.2280055,0 9.2280055,32 0,32z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -782,7 +853,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup.Children>
<GeometryDrawing Geometry="M38.642,39.289c-3.895-3.373-2.645-7.564-0.338-13.896c1.898-5.21,4.051-11.118,1.445-16.945 c-1.789-4.001-6.2-8.319-13.215-8.442L25.963,0c-2.518,0-6.289,0.283-9.953,2.734c-0.286,0.191-0.462,0.51-0.472,0.855 c-0.01,0.345,0.148,0.672,0.424,0.879c0.583,0.438,0.94,1.313,1.138,2.049c-2.711,0.486-3.37,1.934-4.01,3.34 c-0.676,1.486-1.443,3.17-5.15,4.794c-1.008,0.442-1.693,1.499-1.789,2.757c-0.092,1.221,0.412,2.334,1.315,2.905 c0.385,0.244,0.778,0.269,1.094,0.289c0.382,0.025,0.657,0.043,1.07,0.409c0.327,0.292,0.593,0.621,0.827,0.912 c0.388,0.481,0.722,0.896,1.268,1.021c0.77,0.181,1.694-0.278,2.761-0.843c0.693-0.368,1.479-0.784,2.073-0.904 c0.754-0.15,1.721-0.323,2.52-0.323c0.684,0,0.909,0.134,0.928,0.114c0.18,1.047-1.972,2.48-3.87,3.745 c-3.333,2.224-7.481,4.988-6.394,9.455c0.17,0.699,0.523,2.123,3.82,3.819C6.66,39.331,1.21,41.742,1.21,43.609 c0,1.244,1.142,2.041,7.165,2.703C12.421,46.757,17.793,47,23.5,47s11.079-0.243,15.125-0.688 c6.022-0.662,7.165-1.459,7.165-2.703C45.79,42.247,42.89,40.596,38.642,39.289z">
<GeometryDrawing.Pen>
<Pen Brush="Black" Thickness="3"/>
<Pen Brush="{mbts:BTSColor UI.icon_foreground}" Thickness="3"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
@@ -794,7 +865,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M27,22.000013C25.346001,22.000013 24,23.345991 24,25.000013 24,26.654005 25.346001,28.000013 27,28.000013 28.653999,28.000013 30,26.654005 30,25.000013 30,23.345991 28.653999,22.000013 27,22.000013z M5,22C3.3460007,22 2,23.346 2,25 2,26.654 3.3460007,28 5,28 6.6540003,28 8,26.654 8,25 8,23.346 6.6540003,22 5,22z M16,2C14.346,2 13,3.3460007 13,5 13,6.6540003 14.346,8 16,8 17.654,8 19,6.6540003 19,5 19,3.3460007 17.654,2 16,2z M16,0C18.757,0 21,2.243 21,5 21,6.2061872 20.570676,7.3139925 19.856814,8.178627L19.749571,8.3023939 26.702677,20.009615 26.74309,20.006532C26.828189,20.002204 26.913844,20.000013 27,20.000013 29.757004,20.000013 32,22.242994 32,25.000013 32,27.757002 29.757004,30.000013 27,30.000013 24.242996,30.000013 22,27.757002 22,25.000013 22,23.104563 23.060166,21.452075 24.618662,20.604373L24.703606,20.560808 18.143555,9.5162544 17.944359,9.6064529C17.346375,9.8598127 16.68925,10 16,10 15.224594,10 14.489846,9.8225756 13.834221,9.5061913L13.749143,9.4625559 7.9581623,20.972196 7.9896793,20.994624C9.2092552,21.907268 10,23.363032 10,25 10,27.757 7.757,30 5,30 2.243,30 0,27.757 0,25 0,22.243 2.243,20 5,20 5.3446255,20 5.6812191,20.035047 6.0064049,20.101764L6.1420031,20.133139 12.151809,8.1885796 12.143186,8.178627C11.429324,7.3139925 11,6.2061872 11,5 11,2.243 13.243,0 16,0z"/>
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M27,22.000013C25.346001,22.000013 24,23.345991 24,25.000013 24,26.654005 25.346001,28.000013 27,28.000013 28.653999,28.000013 30,26.654005 30,25.000013 30,23.345991 28.653999,22.000013 27,22.000013z M5,22C3.3460007,22 2,23.346 2,25 2,26.654 3.3460007,28 5,28 6.6540003,28 8,26.654 8,25 8,23.346 6.6540003,22 5,22z M16,2C14.346,2 13,3.3460007 13,5 13,6.6540003 14.346,8 16,8 17.654,8 19,6.6540003 19,5 19,3.3460007 17.654,2 16,2z M16,0C18.757,0 21,2.243 21,5 21,6.2061872 20.570676,7.3139925 19.856814,8.178627L19.749571,8.3023939 26.702677,20.009615 26.74309,20.006532C26.828189,20.002204 26.913844,20.000013 27,20.000013 29.757004,20.000013 32,22.242994 32,25.000013 32,27.757002 29.757004,30.000013 27,30.000013 24.242996,30.000013 22,27.757002 22,25.000013 22,23.104563 23.060166,21.452075 24.618662,20.604373L24.703606,20.560808 18.143555,9.5162544 17.944359,9.6064529C17.346375,9.8598127 16.68925,10 16,10 15.224594,10 14.489846,9.8225756 13.834221,9.5061913L13.749143,9.4625559 7.9581623,20.972196 7.9896793,20.994624C9.2092552,21.907268 10,23.363032 10,25 10,27.757 7.757,30 5,30 2.243,30 0,27.757 0,25 0,22.243 2.243,20 5,20 5.3446255,20 5.6812191,20.035047 6.0064049,20.101764L6.1420031,20.133139 12.151809,8.1885796 12.143186,8.178627C11.429324,7.3139925 11,6.2061872 11,5 11,2.243 13.243,0 16,0z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -804,8 +875,8 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M106.965,252.716H262.11c5.522,0,10-4.477,10-10v-77.572c0-5.523-4.478-10-10-10h-67.572V10c0-5.523-4.478-10-10-10 h-77.572c-5.522,0-10,4.477-10,10v232.716C96.965,248.239,101.443,252.716,106.965,252.716z M116.965,20h57.572v145.144 c0,5.523,4.478,10,10,10h67.572v57.572H116.965V20z"/>
<GeometryDrawing Brush="Black" Geometry="M417.253,193.93h-77.571c-5.522,0-10,4.477-10,10v67.572H262.11c-5.522,0-10,4.477-10,10v67.572H29.393 c-5.522,0-10,4.477-10,10v77.572c0,5.523,4.478,10,10,10h387.86c5.522,0,10-4.477,10-10V203.93 C427.253,198.407,422.776,193.93,417.253,193.93z M39.393,369.075h290.289v57.572H39.393V369.075z M407.253,426.646h-57.571 v-67.572c0-5.523-4.478-10-10-10H272.11v-57.572h67.572c5.522,0,10-4.477,10-10V213.93h57.571V426.646z"/>
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M106.965,252.716H262.11c5.522,0,10-4.477,10-10v-77.572c0-5.523-4.478-10-10-10h-67.572V10c0-5.523-4.478-10-10-10 h-77.572c-5.522,0-10,4.477-10,10v232.716C96.965,248.239,101.443,252.716,106.965,252.716z M116.965,20h57.572v145.144 c0,5.523,4.478,10,10,10h67.572v57.572H116.965V20z"/>
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}" Geometry="M417.253,193.93h-77.571c-5.522,0-10,4.477-10,10v67.572H262.11c-5.522,0-10,4.477-10,10v67.572H29.393 c-5.522,0-10,4.477-10,10v77.572c0,5.523,4.478,10,10,10h387.86c5.522,0,10-4.477,10-10V203.93 C427.253,198.407,422.776,193.93,417.253,193.93z M39.393,369.075h290.289v57.572H39.393V369.075z M407.253,426.646h-57.571 v-67.572c0-5.523-4.478-10-10-10H272.11v-57.572h67.572c5.522,0,10-4.477,10-10V213.93h57.571V426.646z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
@@ -845,7 +916,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<GeometryDrawing>
<GeometryDrawing.Pen>
<Pen Brush="Black" Thickness="1" />
<Pen Brush="{mbts:BTSColor UI.icon_foreground}" Thickness="1" />
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<GeometryGroup>
@@ -862,7 +933,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black"
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M18.51899,0L29.981999,0 29.981999,32 18.51899,32z M0,0L11.464992,0 11.464992,32 0,32z" />
</DrawingGroup.Children>
</DrawingGroup>
@@ -874,7 +945,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black"
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M23.679005,26.495C23.99901,26.495 24.265014,26.59 24.475017,26.78 24.685019,26.967 24.79102,27.204 24.79102,27.491 24.79102,27.783 24.68802,28.024 24.481016,28.214 24.271013,28.405 24.00301,28.5 23.679005,28.5 23.354001,28.5 23.085997,28.403 22.870994,28.208 22.655991,28.006 22.54899,27.766 22.54899,27.491 22.54899,27.207 22.655991,26.97 22.870994,26.78 23.085997,26.59 23.354001,26.495 23.679005,26.495z M23.734006,19.5C24.110011,19.5 24.460016,19.541 24.785021,19.625 25.110025,19.708 25.392029,19.839 25.632032,20.017 25.874036,20.195 26.062038,20.422 26.19904,20.7 26.333042,20.978 26.401043,21.311 26.401043,21.7 26.401043,21.947 26.373043,22.171 26.316042,22.371 26.259041,22.572 26.17704,22.762 26.067039,22.94 25.958037,23.118 25.822035,23.289 25.660033,23.453 25.498031,23.617 25.311028,23.786 25.101026,23.961 24.959023,24.078 24.835021,24.187 24.72802,24.289 24.620018,24.39 24.531017,24.49 24.460016,24.589 24.389015,24.689 24.335014,24.794 24.299014,24.905 24.262013,25.017 24.244013,25.144 24.244013,25.285 24.244013,25.383 24.257013,25.482 24.283013,25.583 24.310014,25.685 24.345015,25.77 24.390016,25.838L22.791993,25.838C22.751992,25.733 22.719992,25.615 22.697992,25.483 22.674991,25.351 22.663991,25.226 22.663991,25.109 22.663991,24.922 22.681992,24.752 22.718992,24.599 22.754992,24.445 22.809993,24.3 22.882994,24.164 22.955995,24.029 23.046997,23.898 23.155998,23.775 23.266,23.652 23.393002,23.529 23.539003,23.407 23.694005,23.278 23.828007,23.157 23.943009,23.046 24.059011,22.935 24.157012,22.823 24.238013,22.712 24.320014,22.6 24.380015,22.485 24.420015,22.365 24.460016,22.246 24.481016,22.113 24.481016,21.967 24.481016,21.841 24.459016,21.725 24.414016,21.618 24.369015,21.51 24.306014,21.419 24.222013,21.341 24.140012,21.264 24.03901,21.203 23.918009,21.159 23.799007,21.115 23.667005,21.092 23.521003,21.092 23.204998,21.092 22.876994,21.158 22.536989,21.29 22.195985,21.422 21.87398,21.621 21.569976,21.888L21.569976,20.059C21.88298,19.872 22.222985,19.733 22.59099,19.64 22.959995,19.547 23.341001,19.5 23.734006,19.5z M23.985949,18C20.670016,18 17.972007,20.69101 17.972007,24 17.972007,27.309021 20.670016,30 23.985949,30 27.302003,30 30.000989,27.309021 30.000989,24 30.000989,20.69101 27.302003,18 23.985949,18z M14,2C10.968,2 8.5,4.467 8.5,7.5 8.5,10.438219 10.81616,12.84526 13.717461,12.992831L13.973991,12.99934 13.99997,12.999012 14.027442,12.999304 14.28254,12.992831C17.18384,12.84526 19.5,10.438219 19.5,7.5 19.5,4.467 17.032,2 14,2z M14,0C18.136,0 21.5,3.3640003 21.5,7.5 21.5,9.95575 20.314059,12.13934 18.484733,13.508212L18.265061,13.664531 18.342722,13.68891C19.921902,14.202736,21.408062,14.995103,22.721599,16.037384L22.786062,16.089699 22.966662,16.064397C23.300515,16.021905 23.640717,16 23.985949,16 28.405035,16 32.000998,19.588989 32.000998,24 32.000998,28.411011 28.405035,32 23.985949,32 19.566984,32 15.971998,28.411011 15.971998,24 15.971998,20.96743 17.671191,18.323394 20.169134,16.967021L20.4065,16.845489 20.189965,16.712549C18.448412,15.669154,16.455822,15.076083,14.409823,15.006025L14.033219,14.999578 14,15 13.960834,14.999503 13.690718,15.00291C7.2160797,15.166433,1.9999962,20.449734,1.9999962,26.921989L0,26.928989 0,26.921989C0,20.80439,3.9878531,15.595488,9.51441,13.731782L9.7309766,13.661711 9.5152669,13.508212C7.6859417,12.13934 6.5,9.95575 6.5,7.5 6.5,3.3640003 9.8640003,0 14,0z" />
</DrawingGroup.Children>
</DrawingGroup>
@@ -887,7 +958,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M23,14C24.10498,14 25,14.89502 25,16 25,17.10498 24.10498,18 23,18 21.89502,18 21,17.10498 21,16 21,14.89502 21.89502,14 23,14z M16,14C17.105,14 18,14.895 18,16 18,17.105 17.105,18 16,18 14.895,18 14,17.105 14,16 14,14.895 14.895,14 16,14z M9,14C10.105,14 11,14.895 11,16 11,17.105 10.105,18 9,18 7.8950005,18 7,17.105 7,16 7,14.895 7.8950005,14 9,14z M16,2C8.2799997,2 2,8.2800002 2,16 2,23.72 8.2799997,30 16,30 23.72,30 30,23.72 30,16 30,8.2800002 23.72,2 16,2z M16,0C24.822,0 32,7.178 32,16 32,24.822 24.822,32 16,32 7.1780005,32 0,24.822 0,16 0,7.178 7.1780005,0 16,0z" />
</DrawingGroup.Children>
</DrawingGroup>
@@ -900,7 +971,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M299.152955025434,0L496.426178902388,0 268.890046089888,280.247772216797 198.190201729536,367.407897949219 199.87503144145,369.495361328125 271.502137154341,457.706451416016 498.999970406294,738 301.717621773481,738 101.234124153852,491.008697509766 99.5304498374462,488.936553955078 98.6409082114697,490.003173828125 0,368.488952636719 98.6409082114697,246.945526123047z" />
</DrawingGroup.Children>
</DrawingGroup>
@@ -937,7 +1008,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M 5.3507926 32.045363 H 17.81645 v 2.401501 H 5.3507926 Z m 0 -4.937233 H 24.132995 v 2.401501 H 5.3507926 Z M 18.799228 22.222041 v 2.32929 h -1.567173 v -2.264886 q -2.179014 -0.01073 -4.057475 -0.987533 v -2.973336 q 0.622575 0.504501 1.856993 0.933864 1.234417 0.429362 2.200482 0.493766 v -3.907198 q -2.511771 -0.933863 -3.4349 -2.018003 -0.912395 -1.094874 -0.912395 -2.662047 0 -1.685248 1.191482 -2.8659947 1.19148 -1.1914807 3.155813 -1.3846939 V 4.918734 h 1.567173 v 1.9535992 q 2.264887 0.1073411 3.38123 0.7299162 V 10.500446 Q 20.677689 9.5880506 18.799228 9.3841034 v 4.0682086 q 2.35076 0.847992 3.370495 1.942866 1.019736 1.08414 1.019736 2.629845 0 1.781854 -1.137811 2.876728 -1.13781 1.08414 -3.25242 1.32029 z M 17.232055 12.829737 V 9.4270397 q -1.492034 0.2683516 -1.492034 1.5564393 0 1.105608 1.492034 1.846258 z m 1.567173 3.628113 v 3.25242 q 1.53497 -0.236149 1.53497 -1.53497 0 -1.051939 -1.53497 -1.71745 z m 13.258587 13.65074 h -3.954117 l 0.0014 7.641804 -7.643169 -10e-7 0.0014 3.952751 h 7.640439 l 0.0014 7.641803 h 3.951385 l 0.0014 -7.641802 7.640437 -10e-7 0.0014 -3.952751 -7.643169 10e-7 z M 5.3507926 36.982596 h 5.5381524 v 2.401501 H 5.3507926 Z M 1.3730469 0 A 1.3741374 1.3741374 0 0 0 0 1.3730469 V 45.630859 a 1.3741374 1.3741374 0 0 0 1.3730469 1.373047 H 16.853516 a 17.906029 17.906029 0 0 1 -0.05859 -1.373047 17.906029 17.906029 0 0 1 0.06836 -1.375 H 2.7480469 V 2.7480469 H 33.326172 V 27.783203 a 17.906029 17.906029 0 0 1 1.375 -0.05859 17.906029 17.906029 0 0 1 1.373047 0.06836 V 1.3730469 A 1.3741374 1.3741374 0 0 0 34.701172 0 Z" />
</DrawingGroup.Children>
</DrawingGroup>
@@ -949,7 +1020,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="m 26.463403 27.963318 h -2.359042 l -0.683586 -2.137882 h -3.417929 l -0.676884 2.137882 h -2.345638 l 3.498351 -9.610414 h 2.566798 z M 22.92484 24.163384 21.89276 20.933106 q -0.113931 -0.361899 -0.160844 -0.864535 h -0.05361 q -0.03351 0.422214 -0.167545 0.837727 l -1.045485 3.257086 z m 2.065112 7.055953 -1.51223 1.51223 2.923087 2.922042 -2.923087 2.923086 1.51223 1.511185 2.922042 -2.922042 2.923086 2.922042 1.511185 -1.511185 -2.922041 -2.923086 2.922041 -2.922042 -1.511185 -1.51223 -2.923086 2.923087 z m -9.484387 0.416058 h 6.108175 v 1.176737 h -6.108175 z m 0 -2.419244 h 9.203284 v 1.176735 h -9.203284 z m 0 4.83849 h 2.713696 v 1.176736 H 15.505565 Z M 13.556469 15.93316 a 0.67332766 0.67332766 0 0 0 -0.672794 0.672793 v 21.686339 a 0.67332766 0.67332766 0 0 0 0.672794 0.672793 h 7.585433 a 8.7739586 8.7739586 0 0 1 -0.02871 -0.672793 8.7739586 8.7739586 0 0 1 0.0335 -0.673751 H 14.230219 V 17.279703 h 14.983289 v 12.267233 a 8.7739586 8.7739586 0 0 1 0.67375 -0.02871 8.7739586 8.7739586 0 0 1 0.672794 0.0335 V 16.605953 A 0.67332766 0.67332766 0 0 0 29.887258 15.93316 Z" />
</DrawingGroup.Children>
</DrawingGroup>
@@ -961,7 +1032,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="m 24.706673 31.196264 -3.086181 3.086182 5.96548 5.963348 -5.96548 5.96548 3.086181 3.084049 5.963348 -5.963348 5.96548 5.963348 3.084049 -3.084049 -5.963347 -5.96548 5.963347 -5.963348 -3.084049 -3.086182 -5.96548 5.965481 z M 5.3507926 32.045363 H 17.81645 v 2.401501 H 5.3507926 Z m 0 -4.937233 H 24.132994 v 2.401501 H 5.3507926 Z M 26.434166 6.0031559 14.993666 17.443656 9.6399578 12.089946 6.0100982 15.719802 c 2.9622322 2.959826 6.0772448 6.092263 8.9969908 8.970151 L 30.064121 9.6329208 Z M 5.3507926 36.982596 h 5.5381524 v 2.401501 H 5.3507926 Z M 1.3730469 0 A 1.3741374 1.3741374 0 0 0 0 1.3730469 V 45.630859 a 1.3741374 1.3741374 0 0 0 1.3730469 1.373047 H 16.853516 a 17.906029 17.906029 0 0 1 -0.05859 -1.373047 17.906029 17.906029 0 0 1 0.06836 -1.375 H 2.7480469 V 2.7480469 H 33.326172 V 27.783203 a 17.906029 17.906029 0 0 1 1.375 -0.05859 17.906029 17.906029 0 0 1 1.373047 0.06836 V 1.3730469 A 1.3741374 1.3741374 0 0 0 34.701172 0 Z" />
</DrawingGroup.Children>
</DrawingGroup>
@@ -972,7 +1043,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black"
<GeometryDrawing Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="m 18.887708 18.355738 v 1.910329 h -1.285291 v -1.857509 q -1.787082 -0.0088 -3.327671 -0.809909 v -2.438532 q 0.510595 0.413758 1.522982 0.765893 1.012387 0.352134 1.804689 0.404954 V 13.12654 q -2.059987 -0.765892 -2.817076 -1.655032 -0.748286 -0.897943 -0.748286 -2.1832341 0 -1.382128 0.977174 -2.3504979 0.977173 -0.9771733 2.588188 -1.1356339 V 4.1647166 h 1.285291 v 1.6022121 q 1.85751 0.088034 2.77306 0.5986287 v 2.376908 Q 20.428297 7.9941795 18.887708 7.8269156 V 11.16339 q 1.927937 0.695466 2.764256 1.593409 0.83632 0.88914 0.83632 2.156824 0 1.461358 -0.933157 2.359301 -0.933156 0.88914 -2.667419 1.082814 z M 17.602417 10.652795 V 7.8621291 q -1.223667 0.2200841 -1.223667 1.2764876 0 0.9067463 1.223667 1.5141783 z m 1.285291 2.975537 v 2.667419 q 1.258881 -0.193674 1.258881 -1.258881 0 -0.86273 -1.258881 -1.408538 z M 7.8581956 26.412174 H 18.081699 v 1.969551 H 7.8581956 Z m 0 -4.04919 H 23.262109 v 1.969551 H 7.8581956 Z m 23.8237084 -0.610988 -12.064762 12.064763 4.39301 4.393009 12.064761 -12.064762 z m -0.0014 3.48158 0.91143 0.91143 -8.583182 8.583183 -0.91143 -0.91143 z m -12.817392 9.398532 -1.583992 5.915617 5.914283 -1.585326 z M 7.8581956 30.461364 H 12.40022 v 1.969551 H 7.8581956 Z M 4.5959132 0.13069836 A 1.1269761 1.1269761 0 0 0 3.4698314 1.2567801 V 37.554094 a 1.1269761 1.1269761 0 0 0 1.1260818 1.126082 H 15.310509 a 8.0150307 8.0150307 0 0 1 -0.01762 -0.337985 8.0150307 8.0150307 0 0 1 0.240273 -1.915781 H 5.7235967 V 2.3844637 H 30.801741 V 20.486667 a 8.0150307 8.0150307 0 0 1 0.863383 -0.04966 8.0150307 8.0150307 0 0 1 1.390383 0.12334 V 1.2567801 A 1.1269761 1.1269761 0 0 0 31.929425 0.13069836 Z" />
</DrawingGroup.Children>
</DrawingGroup>
@@ -1008,7 +1079,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M 9.9417804 -0.02293875 1.9154138 8.0034278 17.4301 23.512569 1.9154138 39.027256 9.9417804 47.048077 25.450922 31.538936 40.965607 47.048077 48.986428 39.027256 33.47729 23.512569 48.986428 8.0034278 40.965607 -0.02293875 25.450922 15.491746 Z" />
</DrawingGroup.Children>
</DrawingGroup>
@@ -1021,7 +1092,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="m 69.641861 87.129943 a 36.813842 36.813842 0 0 0 -36.813776 36.813767 36.813842 36.813842 0 0 0 31.044618 36.31355 l 1.208194 21.35839 1.804543 31.90967 a 41.092964 41.092964 0 0 0 -29.828154 39.50509 41.092964 41.092964 0 0 0 41.09258 41.0931 41.092964 41.092964 0 0 0 41.093104 -41.0931 41.092964 41.092964 0 0 0 -0.10284 -2.9068 41.092964 41.092964 0 0 0 -38.048841 -38.03902 l -2.962092 -52.36321 a 36.813842 36.813842 0 0 0 20.093347 -12.61939 l 33.150946 15.70705 v 5.3e-4 a 27.542416 27.542416 0 0 0 -0.12557 2.49907 27.542416 27.542416 0 0 0 27.54251 27.54249 27.542416 27.542416 0 0 0 27.5425 -27.5425 27.542416 27.542416 0 0 0 -27.5425 -27.5425 27.542416 27.542416 0 0 0 -22.44618 11.61479 l -31.44563 -14.89935 a 36.813842 36.813842 0 0 0 1.55701 -10.53786 36.813842 36.813842 0 0 0 -36.813769 -36.813767 z" />
</DrawingGroup.Children>
</DrawingGroup>
@@ -1033,7 +1104,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M 36.50044 86.999995 A 36.813842 36.813842 0 0 0 -0.3133356 123.81377 36.813842 36.813842 0 0 0 30.731282 160.12732 l 1.208194 21.35839 1.804543 31.90967 a 41.092964 41.092964 0 0 0 -29.8281546 39.50509 41.092964 41.092964 0 0 0 41.0925806 41.0931 41.092964 41.092964 0 0 0 41.093099 -41.0931 41.092964 41.092964 0 0 0 -0.102836 -2.9068 41.092964 41.092964 0 0 0 -38.04884 -38.03902 l -2.962092 -52.36321 a 36.813842 36.813842 0 0 0 20.093347 -12.61939 l 33.150948 15.70705 v 5.3e-4 a 27.542416 27.542416 0 0 0 -0.125574 2.49907 27.542416 27.542416 0 0 0 27.542513 27.54249 27.542416 27.542416 0 0 0 27.5425 -27.5425 27.542416 27.542416 0 0 0 -27.5425 -27.5425 27.542416 27.542416 0 0 0 -22.44618 11.61479 L 71.757201 134.35163 A 36.813842 36.813842 0 0 0 73.314213 123.81377 36.813842 36.813842 0 0 0 36.50044 86.999995 Z m 116.60981 115.628085 0.007 37.48967 h -37.49716 l 0.007 19.39257 h 37.48344 L 153.11751 297 h 19.38493 l 0.007 -37.48968 h 37.48342 L 210 240.11775 h -37.49727 l 0.007 -37.48967 z" />
</DrawingGroup.Children>
</DrawingGroup>
@@ -1045,7 +1116,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M 37.03498 86.999995 A 36.813842 36.813842 0 0 0 0.22120379 123.81377 36.813842 36.813842 0 0 0 31.265822 160.12731 l 1.208194 21.35839 1.804543 31.90967 a 41.092964 41.092964 0 0 0 -29.8281552 39.50509 41.092964 41.092964 0 0 0 41.0925812 41.0931 41.092964 41.092964 0 0 0 41.093099 -41.0931 41.092964 41.092964 0 0 0 -0.102836 -2.9068 41.092964 41.092964 0 0 0 -38.04884 -38.03902 l -2.962092 -52.36321 a 36.813842 36.813842 0 0 0 20.093346 -12.61938 l 33.150949 15.70704 v 5.3e-4 a 27.542416 27.542416 0 0 0 -0.125574 2.49907 27.542416 27.542416 0 0 0 27.542503 27.54249 27.542416 27.542416 0 0 0 27.5425 -27.5425 27.542416 27.542416 0 0 0 -27.5425 -27.54249 27.542416 27.542416 0 0 0 -22.44618 11.61479 L 72.29174 134.35163 A 36.813842 36.813842 0 0 0 73.848752 123.81377 36.813842 36.813842 0 0 0 37.03498 86.999995 Z m 94.72671 153.117755 0.008 18.80608 c 0 0 -6.42588 -1.1e-4 78.75576 1.3e-4 l 0.009 -18.80621 c 0 0 4.48208 0 -78.77178 0 z" />
</DrawingGroup.Children>
</DrawingGroup>
@@ -1058,7 +1129,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M 37.03498 86.999995 A 36.813842 36.813842 0 0 0 0.2212037 123.81377 36.813842 36.813842 0 0 0 31.265822 160.12732 l 1.208194 21.35839 1.804543 31.90967 a 41.092964 41.092964 0 0 0 -29.8281553 39.50509 41.092964 41.092964 0 0 0 41.0925813 41.0931 41.092964 41.092964 0 0 0 41.093099 -41.0931 41.092964 41.092964 0 0 0 -0.102836 -2.9068 41.092964 41.092964 0 0 0 -38.04884 -38.03902 l -2.962092 -52.36321 a 36.813842 36.813842 0 0 0 20.093347 -12.61939 l 33.150948 15.70705 v 5.3e-4 a 27.542416 27.542416 0 0 0 -0.125574 2.49907 27.542416 27.542416 0 0 0 27.542503 27.54249 27.542416 27.542416 0 0 0 27.5425 -27.5425 27.542416 27.542416 0 0 0 -27.5425 -27.5425 27.542416 27.542416 0 0 0 -22.44618 11.61479 L 72.291741 134.35163 A 36.813842 36.813842 0 0 0 73.848753 123.81377 36.813842 36.813842 0 0 0 37.03498 86.999995 Z m 145.03189 90.486735 -76.71431 76.71435 27.93311 27.93293 L 210 205.41986 Z m -0.008 22.13769 5.79522 5.79544 -54.57645 54.57644 -5.7952 -5.79522 z m -81.50016 59.76108 -10.071854 37.61451 37.606034 -10.0803 z" />
</DrawingGroup.Children>
</DrawingGroup>
@@ -1070,7 +1141,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="m 139.80129 180.78831 a 20.783495 20.783495 0 0 0 -20.78345 20.78346 20.783495 20.783495 0 0 0 17.52643 20.50105 l 0.68209 12.05803 1.01877 18.01482 a 23.1993 23.1993 0 0 0 -16.83968 22.30284 23.1993 23.1993 0 0 0 23.1991 23.19938 23.1993 23.1993 0 0 0 23.19935 -23.19938 23.1993 23.1993 0 0 0 -0.058 -1.64105 23.1993 23.1993 0 0 0 -21.4807 -21.47518 l -1.67225 -29.56198 a 20.783495 20.783495 0 0 0 11.34383 -7.12437 l 18.71558 8.86752 v 3.1e-4 a 15.549251 15.549251 0 0 0 -0.0708 1.41086 15.549251 15.549251 0 0 0 15.5493 15.54927 15.549251 15.549251 0 0 0 15.54931 -15.54927 15.549251 15.549251 0 0 0 -15.54931 -15.54932 15.549251 15.549251 0 0 0 -12.67213 6.5572 l -17.75282 -8.41152 a 20.783495 20.783495 0 0 0 0.87902 -5.94921 20.783495 20.783495 0 0 0 -20.78345 -20.78346 z M 31.983713 88.265691 A 30.676234 30.676234 0 0 0 1.3075339 118.94187 30.676234 30.676234 0 0 0 27.17639 149.20122 l 1.006764 17.79752 1.503689 26.58969 A 34.241941 34.241941 0 0 0 4.8316412 226.50722 34.241941 34.241941 0 0 0 39.073263 260.74928 34.241941 34.241941 0 0 0 73.315316 226.50722 34.241941 34.241941 0 0 0 73.229625 224.08505 34.241941 34.241941 0 0 0 41.524291 192.3879 L 39.05604 148.75469 A 30.676234 30.676234 0 0 0 55.799422 138.2392 l 27.624018 13.08837 v 4.4e-4 a 22.950541 22.950541 0 0 0 -0.104638 2.08242 22.950541 22.950541 0 0 0 22.950618 22.9506 22.950541 22.950541 0 0 0 22.95062 -22.9506 22.950541 22.950541 0 0 0 -22.95062 -22.95061 22.950541 22.950541 0 0 0 -18.703946 9.67837 L 61.362463 127.72286 A 30.676234 30.676234 0 0 0 62.65989 118.94187 30.676234 30.676234 0 0 0 31.983713 88.265691 Z" />
</DrawingGroup.Children>
</DrawingGroup>
@@ -1082,7 +1153,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M22.889013,19.178117C23.365026,19.178117 23.75202,19.56508 23.75202,20.040055 23.75202,20.516007 23.365026,20.904069 22.889013,20.904069 22.413031,20.904069 22.02503,20.516007 22.02503,20.040055 22.02503,19.56508 22.413031,19.178117 22.889013,19.178117z M22.889013,15.528093C20.40003,15.528092 18.375006,17.552018 18.375006,20.040055 18.375006,22.529069 20.40003,24.554093 22.889013,24.554093 25.37702,24.554093 27.402014,22.529069 27.402014,20.040055 27.402014,17.552018 25.37702,15.528092 22.889013,15.528093z M22.167028,12.426042L23.834021,12.426042 23.834021,13.935075 23.981024,13.958024C24.912024,14.12404,25.772009,14.500016,26.509008,15.03505L26.62702,15.12404 27.757025,13.993058 28.935034,15.171037 27.806005,16.301042 27.940008,16.484025C28.422033,17.167008,28.769018,17.950089,28.943029,18.796037L28.996008,19.093034 30.500006,19.093034 30.500006,20.759049 29.02503,20.759049 28.997015,20.980119C28.848028,21.952043,28.472021,22.85109,27.924017,23.619035L27.805029,23.779069 28.935034,24.909074 27.757025,26.088029 26.62702,24.958024 26.61701,24.966081C25.866034,25.536027,24.981024,25.938004,24.019018,26.117082L23.834021,26.147111 23.834021,27.426042 22.167028,27.426042 22.167028,26.177018 21.949011,26.149064C20.942022,25.995011,20.014013,25.596086,19.228033,25.016007L19.151007,24.957047 18.019018,26.088029 16.841009,24.909074 17.972021,23.779069 17.863013,23.633073C17.294012,22.839005,16.908026,21.905046,16.767034,20.894059L16.75202,20.759049 15.500006,20.759049 15.500006,19.093034 16.783026,19.093034 16.812017,18.91005C16.991034,17.947038,17.393011,17.063004,17.963019,16.312028L17.972021,16.301042 16.841009,15.171037 18.019018,13.993058 19.15003,15.123063 19.310034,15.005021C20.078009,14.458024,20.977026,14.081071,21.949011,13.932023L22.167028,13.905046z M16.000014,6.0000114C14.346014,6.0000114 13.000014,7.3460112 13.000014,9.0000114 13.000014,10.654011 14.346014,12.000011 16.000014,12.000011 17.654014,12.000011 19.000014,10.654011 19.000014,9.0000114 19.000014,7.3460112 17.654014,6.0000114 16.000014,6.0000114z M16.000014,4.0000114C18.757014,4.0000114 21.000014,6.2430115 21.000014,9.0000114 21.000014,11.757011 18.757014,14.000011 16.000014,14.000011 13.243014,14.000011 11.000014,11.757011 11.000014,9.0000114 11.000014,6.2430115 13.243014,4.0000114 16.000014,4.0000114z M16.000123,0C24.651189,0 31.47924,8.0160384 31.765244,8.3580403 32.078245,8.7290418 32.078245,9.2720447 31.765244,9.6440461 31.700243,9.7220466 30.130231,11.580056 27.56321,13.533065L26.352201,11.941058C27.853213,10.798052 29.000222,9.6770465 29.645226,9.0010433 27.881213,7.1610341 22.366171,2.0000095 16.000123,2.0000095 9.6350741,2.0000095 4.1210318,7.1590343 2.3550186,9.0000434 4.013031,10.731052 8.9770689,15.388074 14.846114,15.946077L14.657112,17.936087C6.6410513,17.175083 0.49200439,9.9510479 0.23400211,9.6430461 -0.078000069,9.2720447 -0.078000069,8.7290418 0.23400211,8.3580403 0.52000427,8.0160384 7.3480568,0 16.000123,0z"
/>
</DrawingGroup.Children>
@@ -1095,7 +1166,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M23.471008,4.2230202L32,12.800012 23.471008,20.360005 23.471008,16.322012C23.471008,16.322012 8.7430115,12.294 5.0610046,20.360005 5.0610046,18.343985 6.3990173,8.2560073 23.471008,8.2560073z M0,0L21.334015,0 21.334015,2.1340014 21.334015,4.2690102 19.200012,4.2690102 19.200012,2.1340014 2.1340027,2.1340014 2.1340027,23.466997 19.200012,23.466997 19.200012,21.331989 21.334015,21.331989 21.334015,23.466997 21.334015,25.601 19.200012,25.601 0,25.601 0,23.466997 0,2.1340014z"
/>
</DrawingGroup.Children>
@@ -1108,7 +1179,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M13.594002,4.2219891L13.594002,8.255989C30.661003,8.255989 32,18.345018 32,20.360004 28.319,12.293011 13.594002,16.32399 13.594002,16.32399L13.594002,20.360004 5.0610008,12.798993z M0,0L21.333,0 21.333,2.1329974 21.333,4.2670025 19.201,4.2670025 19.201,2.1329974 2.1330032,2.1329974 2.1330032,23.467003 19.201,23.467003 19.201,21.332998 21.333,21.332998 21.333,23.467003 21.333,25.6 19.201,25.6 0,25.6 0,23.467003 0,2.1329974z"
/>
</DrawingGroup.Children>
@@ -1121,7 +1192,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M25.400009,21.400005L29.800003,21.400005C28.100006,24.100017 25.400009,26.200025 22.300003,27.200025 23,26.500013 23.600006,25.600019 24.199997,24.600017 24.699997,23.600017 25.100006,22.500011 25.400009,21.400005z M19,21.400005L24,21.400005C23.699997,22.299998 23.300003,23.200023 22.900009,23.900005 21.800003,26.000013 20.400009,27.3 18.900009,27.700025z M12.300003,21.400005L17.699997,21.400005 17.600006,27.8C16,27.600019 14.5,26.200025 13.300003,23.900005 13,23.100017 12.600006,22.299998 12.300003,21.400005z M26.5,14.700019L32,14.700019C31.900009,16.600013,31.400009,18.400003,30.600006,20.100015L25.900009,20.100015C26.199997,18.400003,26.5,16.600013,26.5,14.700019z M19.100006,14.700019L25.199997,14.700019C25.100006,16.600013,24.900009,18.400003,24.400009,20.100015L19,20.100015z M16.199997,14.700019L17.699997,14.700019 17.699997,20.100015 12,20.100015C11.900009,19.799997,11.900009,19.500009,11.800003,19.200021L15.5,15.500007z M25.900009,7.7999913L30.600006,7.7999913C31.400009,9.500004,31.900009,11.399999,32,13.4L26.5,13.4C26.5,11.399999,26.300003,9.500004,25.900009,7.7999913z M19.100006,7.7999913L24.5,7.7999913C24.900009,9.500004,25.199997,11.399999,25.199997,13.4L19.100006,13.4z M12.100006,7.7999913L17.800003,7.7999913 17.800003,13.4 11.300003,13.4C11.300003,11.299993,11.600006,9.3999979,12.100006,7.7999913z M22.5,0.6000061C25.600006,1.6000066,28.199997,3.6000077,29.900009,6.3999969L25.600006,6.3999969C25.300003,5.2999904 24.900009,4.2000138 24.400009,3.2999892 23.800003,2.2999887 23.199997,1.3999944 22.5,0.6000061z M14.199997,0.6000061C13.5,1.2999882 12.900009,2.2000131 12.300003,3.2000136 10.900009,5.8999965 10,9.8999988 9.9000092,14.000007L9.9000092,14.700019 14.5,14.700019 7.1999969,22.000011 0,14.600013 4.5,14.600013 4.5,13.900001C4.5,7.7000157,8.6000061,2.2999887,14.199997,0.6000061z M19.199997,0.1000061C20.600006,0.50000006 22,1.7999884 23.100006,3.8999953 23.5,4.7000143 23.800003,5.5000026 24.100006,6.3999969L19.100006,6.3999969z M17.900009,0L17.800003,6.3999969 12.400009,6.3999969C12.699997,5.5000026 13.100006,4.6000082 13.5,3.7999892 14.699997,1.5000005 16.300003,0.20001213 17.900009,0z"
/>
</DrawingGroup.Children>
@@ -1133,9 +1204,9 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Geometry="{StaticResource arrow_geometry}">
<GeometryDrawing Geometry="{Binding Source={StaticResource {x:Static mbts:Icons.ArrowGeometryKey}}}">
<GeometryDrawing.Pen>
<Pen Thickness="3" Brush="Black"/>
<Pen Thickness="3" Brush="{mbts:BTSColor UI.icon_foreground}"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
@@ -1147,9 +1218,9 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Geometry="{StaticResource arrow_geometry}">
<GeometryDrawing Geometry="{Binding Source={StaticResource {x:Static mbts:Icons.ArrowGeometryKey}}}">
<GeometryDrawing.Pen>
<Pen Thickness="3" Brush="Black"/>
<Pen Thickness="3" Brush="{mbts:BTSColor UI.icon_foreground}"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
@@ -1165,7 +1236,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M21.832001,24.424L21.832001,27.912998 26.218018,27.912998 26.218018,24.424z M13.757019,24.424L13.757019,27.912998 18.143005,27.912998 18.143005,24.424z M5.7820129,24.424L5.7820129,27.912998 10.167999,27.912998 10.167999,24.424z M1.8950195,6.3799964L3.8880005,6.3799964 4.1870117,17.745001 8.1750183,17.745001 8.1750183,13.956 16.050018,17.745001 16.149994,17.745001 16.149994,13.956 24.024994,17.745001 24.125,17.745001 24.125,13.956 32,17.745001 31.901001,17.745001 31.901001,31.103001 0,31.103001 0,17.745001 1.5950012,17.745001z M8.5740051,1.3959956C8.5740051,1.3959958 9.1719971,3.2899927 6.6800232,3.5889963 6.6800232,3.5889963 5.085022,3.6879953 4.2870178,4.4859993 4.2870178,4.4859993 3.9880066,4.7849952 3.8880005,4.4859993 3.8880005,4.4859993 3.9880066,3.0899958 6.480011,2.6919931 6.5800171,2.7909998 8.3740234,2.6919931 8.5740051,1.3959956z M5.5830078,0C5.5830078,-1.4470834E-07 6.8789978,1.4949948 4.5859985,2.6919931 4.5859985,2.6919931 3.1900024,3.2899927 2.6920166,4.3859931 2.6920166,4.3859931 2.5920105,4.7849952 2.2929993,4.4859993 2.2929993,4.4859993 1.8950195,3.1899942 4.0880127,1.8939967 4.1870117,1.9939953 5.882019,1.2959973 5.5830078,0z"
/>
</DrawingGroup.Children>
@@ -1178,7 +1249,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M12,16A2,2 0 0,1 14,18A2,2 0 0,1 12,20A2,2 0 0,1 10,18A2,2 0 0,1 12,16M12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12A2,2 0 0,1 12,10M12,4A2,2 0 0,1 14,6A2,2 0 0,1 12,8A2,2 0 0,1 10,6A2,2 0 0,1 12,4Z"
/>
</DrawingGroup.Children>
@@ -1192,7 +1263,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Brush="{mbts:BTSColor UI.icon_foreground}"
Geometry="M 0.814453 2e-6 C 0.365092 -7.56e-4 3.21e-4 0.36314 0 0.812502 v 23.945313 c 0.788895 1.126154 1.626953 -0.02112 1.626953 -0.02112 V 1.625002 h 16.241843 c 0 0 0.80538 -0.934678 -0.124651 -1.625002 z M 3.750875 3.43624 C 3.301514 3.435482 2.936743 3.799378 2.936422 4.24874 v 23.945313 c -7.6e-4 0.450124 0.364329 0.815213 0.814453 0.814453 h 7.439453 C 11.042745 28.716852 10.90913 28.418337 10.789937 28.113975 10.699431 27.872971 10.617994 27.628659 10.545796 27.381553 H 4.563375 V 5.06124 h 15.304687 v 7.039063 c 0.173002 -0.01023 0.346234 -0.01609 0.519531 -0.01758 0.343731 -2.6e-4 0.68726 0.01669 1.029297 0.05078 0.02606 0.0038 0.0521 0.0077 0.07813 0.01172 V 4.248738 C 21.494699 3.799376 21.129928 3.43548 20.680567 3.436238 Z m 13.332031 6.884766 c -1.226661 0 -2.230469 1.002456 -2.230469 2.228516 v 9.572265 l -0.824219 -0.8125 v 0.002 c -0.991917 -0.9815 -2.60964 -0.982302 -3.603515 0 -0.48293 0.477155 -0.751953 1.119962 -0.751953 1.796875 0 0.67607 0.269215 1.317958 0.751953 1.794922 l 4.841797 4.78711 0.0078 0.0078 c 2.115591 1.851014 4.144077 2.322266 5.615234 2.322266 0.547268 0 1.017683 -0.06414 1.388672 -0.142578 1.701281 -0.360558 3.108561 -1.372782 3.751954 -2.75586 0.419048 -0.9011 0.978455 -2.062137 0.923828 -3.261718 4.09e-4 -0.01025 0.0011 -0.0075 0.002 -0.02344 0.0015 -0.02655 0.0039 -0.01047 0.0039 -0.07813 v -5.113281 c 0 -1.161114 -0.955476 -2.109375 -2.121094 -2.109375 -0.04803 0 -0.09044 0.0088 -0.136719 0.01172 -0.207784 -1.015547 -1.021531 -1.826172 -2.095703 -1.826172 -0.343265 0 -0.63914 0.145124 -0.93164 0.285156 -0.397916 -0.616533 -1.045784 -1.0625 -1.830078 -1.0625 -0.189487 0 -0.354735 0.07615 -0.53125 0.121094 v -3.515625 c 0 -1.22606 -1.003809 -2.228516 -2.230469 -2.228516 z m 0 1.699219 c 0.148476 0 0.278642 0.05997 0.375 0.15625 0.09685 0.09678 0.15625 0.225142 0.15625 0.373047 v 5.625 1.740234 c 0 0.464846 0.384763 0.849609 0.849609 0.849609 0.464527 0 0.84961 -0.383921 0.84961 -0.849609 v -1.740234 c 0 -0.148598 0.05896 -0.275762 0.15625 -0.373047 0.09729 -0.09729 0.228277 -0.158203 0.375 -0.158203 0.146722 0 0.277709 0.06091 0.375 0.158203 0.09729 0.09729 0.15625 0.224449 0.15625 0.373047 v 0.77539 0.4375 c 0 0.465373 0.384236 0.84961 0.849609 0.84961 0.465373 0 0.849609 -0.384239 0.849609 -0.84961 v -0.425781 l 0.0059 -0.06836 c 0.0286 -0.265146 0.249414 -0.472657 0.52539 -0.472657 0.148238 0 0.278481 0.05996 0.375 0.15625 0.09649 0.09627 0.15625 0.225145 0.15625 0.373047 v 1.935547 c 0 0.465371 0.384237 0.84961 0.84961 0.84961 0.465372 0 0.849609 -0.384237 0.849609 -0.84961 v -0.65039 c 0.0016 -9e-6 2.95e-4 0 0.002 0 0.238806 0 0.421875 0.185008 0.421875 0.410156 l 0.002 5.0625 c -4.64e-4 0.0084 -0.0023 0.0401 -0.0039 0.07227 -0.0015 0.03041 -0.0059 0.02687 -0.002 0.101563 0.03253 0.757506 -0.372777 1.677807 -0.765625 2.521484 h -0.002 c -0.194342 0.418116 -0.532821 0.810028 -0.976563 1.126953 -0.443595 0.316821 -0.990203 0.55925 -1.585937 0.685547 -0.515602 0.10823 -1.298166 0.179402 -2.248047 -0.03125 -0.47546 -0.105441 -0.991926 -0.281044 -1.539063 -0.560547 -0.547306 -0.279588 -1.127683 -0.66381 -1.724609 -1.185547 L 11.620061 23.69601 c -0.162198 -0.160763 -0.248047 -0.365899 -0.248047 -0.587891 0 -0.223284 0.08648 -0.426518 0.248047 -0.585937 0.168295 -0.166151 0.386826 -0.249911 0.607422 -0.25 0.220595 -9e-5 0.437432 0.08144 0.605469 0.248047 l 2.240234 2.207031 0.01367 0.02148 0.04687 0.03516 0.03711 0.0332 0.02539 0.01758 0.01563 0.01367 0.01563 0.0098 c 0.114637 0.07747 0.248043 0.126397 0.388672 0.140625 l -0.04883 -0.0078 0.04102 0.0098 0.08594 0.0039 h 0.0078 c 0.06844 0 0.126002 -0.0085 0.169922 -0.01758 l 0.0059 -0.002 0.01953 -0.0039 h 0.02539 l 0.06641 -0.02734 0.02734 -0.0098 0.0098 -0.0039 c 0.102105 -0.04223 0.198238 -0.105586 0.28125 -0.189454 h 0.002 c 0.163006 -0.165519 0.243191 -0.385955 0.242188 -0.599609 v -0.002 -0.01953 -11.580078 c 0 -0.147904 0.0594 -0.276271 0.15625 -0.373047 0.09636 -0.09628 0.226522 -0.15625 0.375 -0.15625 z"
/>
</DrawingGroup.Children>
@@ -1,35 +1,37 @@
using bts.api.core;
using bts.api.md.auxiliary;
using mbts.utils;
using System;
using System.Composition;
using System.Reactive.Concurrency;
namespace mbts.spark {
[Export]
class MarketDataAuxiliaryModel : IDisposable {
readonly MarketDataAuxiliaryService _service;
readonly LegacyTableUpdateDemuxer<VolumeAtPriceLevelImmutable, int, uint> _security_orders_demuxer;
IDisposable _dispose;
[ImportingConstructor]
public MarketDataAuxiliaryModel(MarketDataAuxiliaryService service) {
_service = service;
var scheduler = ThreadPoolScheduler.Instance;
var interval = TimeSpan.FromMilliseconds(100);
volume_at_price = service.subscribei_volume_at_price().Naggle(interval, scheduler).Table().Cache();
_security_orders_demuxer = new LegacyTableUpdateDemuxer<VolumeAtPriceLevelImmutable, int, uint>(o => o.RecordId, v => v.SecurityId);
_dispose = volume_at_price.AddRemoveOnly().Subscribe(_security_orders_demuxer);
}
public IObservable<TableUpdate<VolumeAtPriceLevelImmutable, int>> volume_at_price { get; }
public IObservable<ITableUpdateTransform<VolumeAtPriceLevelImmutable, int>> security_volume_at_price(uint security) =>
_security_orders_demuxer.subscribe(security);
public void Dispose() =>
Disposable.dispose(ref _dispose);
}
}
namespace mbts.spark {
using bts.api.core;
using bts.api.md.auxiliary;
using mbts.utils;
using Spark.Core.Reactive;
using System;
using System.Composition;
using System.Reactive.Concurrency;
[Export]
class MarketDataAuxiliaryModel : IDisposable {
readonly MarketDataAuxiliaryService _service;
readonly TableUpdateDemuxer<VolumeAtPriceLevelImmutable, int, uint> _security_orders_demuxer;
IDisposable _dispose;
[ImportingConstructor]
public MarketDataAuxiliaryModel(MarketDataAuxiliaryService service) {
_service = service;
var scheduler = ThreadPoolScheduler.Instance;
var interval = TimeSpan.FromMilliseconds(100);
volume_at_price = service.subscribei_volume_at_price().Naggle(interval, scheduler).Table().Cache();
_security_orders_demuxer = new(o => o.RecordId, v => v.SecurityId);
_dispose = volume_at_price.Subscribe(_security_orders_demuxer);
}
public IObservable<TableUpdate<VolumeAtPriceLevelImmutable, int>> volume_at_price { get; }
public IObservable<TableUpdate<VolumeAtPriceLevelImmutable, int>> security_volume_at_price(uint security) =>
_security_orders_demuxer.subscribe(security);
public void Dispose() =>
Disposable.dispose(ref _dispose);
}
}
@@ -1,31 +1,31 @@
using bts.utils;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Linq;
namespace mbts.spark {
[ProtoContract]
class GlobalAlertSettings : IEquatable<GlobalAlertSettings> {
[ProtoMember(1)]
TradeAlert[] _trade_alerts;
public GlobalAlertSettings() { }
public GlobalAlertSettings(IEnumerable<TradeAlert> trade_alerts) =>
_trade_alerts = trade_alerts.ToArray();
public IReadOnlyList<TradeAlert> trade_alerts => _trade_alerts ?? Array.Empty<TradeAlert>();
public bool Equals(GlobalAlertSettings other) =>
other != null &&
trade_alerts.SequenceEqual(other.trade_alerts);
public override bool Equals(object obj) =>
Equals(obj as GlobalAlertSettings);
public override int GetHashCode() =>
EqualityComparer.auto_phase(trade_alerts);
}
}
using bts.utils;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Linq;
namespace mbts.spark {
[ProtoContract]
class GlobalAlertSettings : IEquatable<GlobalAlertSettings> {
[ProtoMember(1)]
TradeAlert[] _trade_alerts;
public GlobalAlertSettings() { }
public GlobalAlertSettings(IEnumerable<TradeAlert> trade_alerts) =>
_trade_alerts = trade_alerts.ToArray();
public IReadOnlyList<TradeAlert> trade_alerts => _trade_alerts ?? Array.Empty<TradeAlert>();
public bool Equals(GlobalAlertSettings other) =>
other != null &&
trade_alerts.SequenceEqual(other.trade_alerts);
public override bool Equals(object obj) =>
Equals(obj as GlobalAlertSettings);
public override int GetHashCode() =>
EqualityComparer.auto_phase(trade_alerts);
}
}
@@ -1,88 +1,88 @@
using bts;
using mbts.ui.shell;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Composition;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace mbts.ui.settings {
public interface ISavedWindowFactory {
Task<IShellWindow> restore(WindowState window);
}
[Export(typeof(ISavedWindowFactory))]
public class WindowFactory : ISavedWindowFactory {
IShellWindowMigrationRule[] _compat;
[ImportingConstructor]
public WindowFactory([ImportMany] IShellWindowMigrationRule[] migration) {
_compat = migration;
}
[Import]
public ObservableCollection<IShellModule> modules { get; set; }
public Task<IShellWindow> restore(WindowState window) {
Log.Ui.info("Loading window '{0}'".fmt(window.title));
bool changed;
int count = 0;
do {
count++;
changed = apply_compatability_migrations(ref window);
} while (count < 100 && changed);
if (count == 100) {
Log.Persist.error("Error: Window state migration still changing after 100 iterations. Please check IShellWindowMigrationRule logic.");
}
return restore(window.owner, window.app_data, window.position);
}
/// When we apply the migration changes to a window we stop as soon as one "matches" and updates the state
/// Since it's possible that we have multiple levels of migration we run this function until the data stops changing (or 100 iterations)
/// ex: If change the data format twice from A to B to C then we would write 2 IShellWindowMigration instances.
/// Starting in state A one of the _compat tests changes to state B. Now we need to re-run
/// the migrations because state B will match a different rule and be converted to state C.
private bool apply_compatability_migrations(ref WindowState window) {
foreach (var test in _compat) {
try {
if (test.apply(ref window)) {
return true;
}
} catch (Exception e) {
Log.Persist.error("Exception running compat rule {0}.\n{1}".fmt(test.GetType().Name, e.ToString()));
}
}
return false;
}
private async Task<IShellWindow> restore(string owner_name, byte[] state, WindowPosition windowPosition) {
IShellModule owner = modules.empty_if_null().SingleOrDefault(m => m.key() == owner_name);
if (owner == null) {
Log.Ui.warn("Could not locate module '{0}'".fmt(owner_name));
return null;
}
try {
Task<IShellWindow> task = owner.create(new MemoryStream(state));
if (task != null) {
IShellWindow window = await task;
if (window != null) {
window.set_start_position(windowPosition);
Log.Ui.info($"Restoring window {owner_name} - {window.diagnostic_name()}.");
}
return window;
}
} catch (Exception e) {
Log.Ui.error("Failure to re-create window for module {0}. Error: {1}".fmt(owner_name, e.Message));
}
return null;
}
}
}
using bts;
using mbts.ui.shell;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Composition;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace mbts.ui.settings {
public interface ISavedWindowFactory {
Task<IShellWindow> restore(WindowState window);
}
[Export(typeof(ISavedWindowFactory))]
public class WindowFactory : ISavedWindowFactory {
IShellWindowMigrationRule[] _compat;
[ImportingConstructor]
public WindowFactory([ImportMany] IShellWindowMigrationRule[] migration) {
_compat = migration;
}
[Import]
public ObservableCollection<IShellModule> modules { get; set; }
public Task<IShellWindow> restore(WindowState window) {
Log.Ui.info("Loading window '{0}'".fmt(window.title));
bool changed;
int count = 0;
do {
count++;
changed = apply_compatability_migrations(ref window);
} while (count < 100 && changed);
if (count == 100) {
Log.Persist.error("Error: Window state migration still changing after 100 iterations. Please check IShellWindowMigrationRule logic.");
}
return restore(window.owner, window.app_data, window.position);
}
/// When we apply the migration changes to a window we stop as soon as one "matches" and updates the state
/// Since it's possible that we have multiple levels of migration we run this function until the data stops changing (or 100 iterations)
/// ex: If change the data format twice from A to B to C then we would write 2 IShellWindowMigration instances.
/// Starting in state A one of the _compat tests changes to state B. Now we need to re-run
/// the migrations because state B will match a different rule and be converted to state C.
private bool apply_compatability_migrations(ref WindowState window) {
foreach (var test in _compat) {
try {
if (test.apply(ref window)) {
return true;
}
} catch (Exception e) {
Log.Persist.error("Exception running compat rule {0}.\n{1}".fmt(test.GetType().Name, e.ToString()));
}
}
return false;
}
private async Task<IShellWindow> restore(string owner_name, byte[] state, WindowPosition windowPosition) {
IShellModule owner = modules.empty_if_null().SingleOrDefault(m => m.key() == owner_name);
if (owner == null) {
Log.Ui.warn("Could not locate module '{0}'".fmt(owner_name));
return null;
}
try {
Task<IShellWindow> task = owner.create(new MemoryStream(state));
if (task != null) {
IShellWindow window = await task;
if (window != null) {
window.set_start_position(windowPosition);
Log.Ui.info($"Restoring window {owner_name} - {window.diagnostic_name()}.");
}
return window;
}
} catch (Exception e) {
Log.Ui.error("Failure to re-create window for module {0}. Error: {1}".fmt(owner_name, e.Message));
}
return null;
}
}
}
@@ -1,86 +1,113 @@
using bts;
using mbts.ui.shell;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Composition;
using System.IO;
using System.Linq;
namespace mbts.ui.settings {
public interface ISettingsCollector {
// Get the save state for every open window
IEnumerable<WindowState> get_window_state();
WindowState get_window_state(IShellWindow window);
IEnumerable<ModuleState> get_module_state();
WindowPosition get_launcher_state();
}
[Export(typeof(ISettingsCollector))]
class SettingsCollector : ISettingsCollector {
IWindowsInterop _interop;
IWindowManager _wm;
ILauncher _launcher;
[ImportingConstructor]
public SettingsCollector(IWindowManager wm, IWindowsInterop interop, ILauncher launcher) {
_wm = wm;
_interop = interop;
_launcher = launcher;
}
[Import]
public ObservableCollection<IShellModule> modules { get; set; }
public IEnumerable<WindowState> get_window_state() {
foreach (var window in _wm.list_windows()) {
// Check that the window is still open since we might be iterating asyncronously
if (_wm.contains(window)) {
var state = get_window_state(window);
if (state != null) {
yield return state;
}
}
}
}
public IEnumerable<ModuleState> get_module_state() {
//Note: I'm assuming that the list of modules is stable and I don't have to protect against it changing here
foreach (var module in modules.OfTypeSafe<IPersistShellModule>()) {
MemoryStream out_stream = new MemoryStream();
module.get_state(out_stream);
yield return new ModuleState() {
name = module.key(),
app_data = out_stream.ToArray(),
};
}
}
public WindowPosition get_launcher_state() {
return _launcher.get_position();
}
public WindowState get_window_state(IShellWindow window) {
try {
if (window == null || window.Owner == null) return null;
MemoryStream out_stream = new MemoryStream();
window.GetState(out_stream);
var pos = _interop.GetPosition(window);
var state = new WindowState() {
owner = window.Owner.key(),
app_data = out_stream.ToArray(),
position = pos,
title = string.IsNullOrEmpty(pos.custom_title) ? window.Title : pos.custom_title
};
return state;
} catch (Exception e) {
Log.Ui.error("Error saving window state for type {0}.\n {1}".fmt(window.GetType(), e.Message));
}
return null;
}
}
}
using bts;
using mbts.ui.shell;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Composition;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Threading;
namespace mbts.ui.settings {
public interface ISettingsCollector {
// Get the save state for every open window
Task<List<WindowState>> get_window_state();
Task<WindowState> get_window_state(IShellWindow window);
IEnumerable<ModuleState> get_module_state();
WindowPosition get_launcher_state();
}
[Export(typeof(ISettingsCollector))]
class SettingsCollector : ISettingsCollector {
WindowManager _wm;
ILauncher _launcher;
[ImportingConstructor]
public SettingsCollector(WindowManager wm, ILauncher launcher) {
_wm = wm;
_launcher = launcher;
}
[Import]
public ObservableCollection<IShellModule> modules { get; set; }
[Import]
public IShellThreadFactory thread_factory { get; set; }
IWindowsInterop _interop => _wm;
public async Task<List<WindowState>> get_window_state() {
var windows = _wm.list_windows();
var rv = new List<WindowState>(windows.Count);
foreach (var window in windows) {
// Check that the window is still open since we might be iterating asyncronously
if (_wm.contains(window)) {
var state = await get_window_state(window);
if (state != null) {
rv.Add(state);
}
}
}
return rv;
}
public IEnumerable<ModuleState> get_module_state() {
//Note: I'm assuming that the list of modules is stable and I don't have to protect against it changing here
foreach (var module in modules.OfTypeSafe<IPersistShellModule>()) {
MemoryStream out_stream = new MemoryStream();
module.get_state(out_stream);
yield return new ModuleState() {
name = module.key(),
app_data = out_stream.ToArray(),
};
}
}
public WindowPosition get_launcher_state() {
return _launcher.get_position();
}
public async Task<WindowState> get_window_state(IShellWindow window) {
try {
if (window == null || window.Owner == null) return null;
Dispatcher dispatcher = null;
if (window is ISlowWindow) {
var tf = thread_factory;
if (tf is not null) {
var thread_id = (window as ISharedWindow)?.thread_id;
dispatcher = tf.get_dispatcher(thread_id);
if (dispatcher is null) {
Log.Gen.error(
$"Unable to get window state for '{window.Title}.' " +
$"Didn't find dispatcher for thread {thread_id}.");
return null;
}
}
}
var pos = _interop.GetPosition(window);
var state = new WindowState() {
owner = window.Owner.key(),
app_data = dispatcher is null ?
(await dispatcher.InvokeAsync(serialize)) : serialize(),
position = pos,
title = string.IsNullOrEmpty(pos.custom_title) ? window.Title : pos.custom_title
};
return state;
byte[] serialize() {
using var ms = new MemoryStream();
window.GetState(ms);
return ms.ToArray();
}
} catch (Exception e) {
Log.Ui.error("Error saving window state for type {0}.\n {1}".fmt(window.GetType(), e.Message));
}
return null;
}
}
}
@@ -1,94 +1,95 @@
using bts.shell.pnl;
using bts.utils;
using mbts.ui.settings;
using System;
using System.Collections.Generic;
namespace bts.settings {
interface ISettingsMigrationRule<T> {
bool apply(T settings, out T new_settings);
}
// Migration rules of type ISettingsMigrationRule<T>, where 'T' is a common type, such as GridSettings,
// should be exposed through explicitly named interfaces that inherit ISettingsMigrationRule<T>.
// This avoids magic const names in the MEF import/export contracts, which would otherwise be needed to
// determine the various windows to which such rules apply.
interface IFillsGridSettingsMigrationRule : ISettingsMigrationRule<GridSettings> { }
interface IMarketViewGridSettingsMigrationRule : ISettingsMigrationRule<GridSettings> { }
interface IPAndLGridSettingsMigrationRule : ISettingsMigrationRule<GridSettings> { }
interface IPNLSettingsMigrationRule : ISettingsMigrationRule<PNLSettings> { }
interface ISyntheticManagementMigrationRule : ISettingsMigrationRule<GridSettings> { }
static class SettingsMigrationHelper {
public static bool apply<T>(T settings, IEnumerable<ISettingsMigrationRule<T>> migration_rules, out T new_settings) {
bool applied = false;
foreach (var r in migration_rules) {
if (r.apply(settings, out var migrated)) {
settings = migrated;
applied = true;
}
}
new_settings = applied ? settings : default;
return applied;
}
public static void apply_quiet<T>(ref T settings, IEnumerable<ISettingsMigrationRule<T>> migration_rules) {
if (apply(settings, migration_rules, out var new_settings))
settings = new_settings;
}
public static ISettingsMigrationRule<T> merge<T>(this IEnumerable<ISettingsMigrationRule<T>> rules) =>
new MergeWrapper<T>(rules);
public static ISettingsMigrationRule<TOuter> wrap<TInner, TOuter>(this ISettingsMigrationRule<TInner> rule, IImmutableProperty<TOuter, TInner> propi) =>
new SelectorWrapper<TInner, TOuter>(rule, propi.get, propi.set);
public static ISettingsMigrationRule<TOuter> wrap<TInner, TOuter>(this ISettingsMigrationRule<TInner> rule, Func<TOuter, TInner> get, Func<TOuter, TInner, TOuter> set) =>
new SelectorWrapper<TInner, TOuter>(rule, get, set);
class MergeWrapper<T> : ISettingsMigrationRule<T> {
readonly IEnumerable<ISettingsMigrationRule<T>> _rules;
public MergeWrapper(IEnumerable<ISettingsMigrationRule<T>> rules) =>
_rules = rules;
public bool apply(T settings, out T new_settings) {
bool applied = false;
foreach (var r in _rules) {
if (r.apply(settings, out var migrated)) {
settings = migrated;
applied = true;
}
}
new_settings = applied ? settings : default;
return applied;
}
}
class SelectorWrapper<TInner, TOuter> : ISettingsMigrationRule<TOuter> {
readonly ISettingsMigrationRule<TInner> _rule;
readonly Func<TOuter, TInner> _get;
readonly Func<TOuter, TInner, TOuter> _set;
public SelectorWrapper(ISettingsMigrationRule<TInner> rule, Func<TOuter, TInner> get, Func<TOuter, TInner, TOuter> set) {
_rule = rule;
_get = get;
_set = set;
}
public bool apply(TOuter settings, out TOuter new_settings) {
if (settings != null) {
var ival = _get(settings);
if (_rule.apply(ival, out var new_ival)) {
new_settings = _set(settings, new_ival);
return true;
}
}
new_settings = default;
return false;
}
}
}
}
using bts.shell.pnl;
using bts.utils;
using mbts.ui.settings;
using System;
using System.Collections.Generic;
namespace bts.settings {
interface ISettingsMigrationRule<T> {
bool apply(T settings, out T new_settings);
}
// Migration rules of type ISettingsMigrationRule<T>, where 'T' is a common type, such as GridSettings,
// should be exposed through explicitly named interfaces that inherit ISettingsMigrationRule<T>.
// This avoids magic const names in the MEF import/export contracts, which would otherwise be needed to
// determine the various windows to which such rules apply.
interface IFillsGridSettingsMigrationRule : ISettingsMigrationRule<GridSettings> { }
interface IMarketViewGridSettingsMigrationRule : ISettingsMigrationRule<GridSettings> { }
interface IPAndLGridSettingsMigrationRule : ISettingsMigrationRule<GridSettings> { }
interface IPNLSettingsMigrationRule : ISettingsMigrationRule<PNLSettings> { }
interface ISyntheticManagementMigrationRule : ISettingsMigrationRule<GridSettings> { }
interface IReconcileReportMigrationRule : ISettingsMigrationRule<GridSettings> { }
static class SettingsMigrationHelper {
public static bool apply<T>(T settings, IEnumerable<ISettingsMigrationRule<T>> migration_rules, out T new_settings) {
bool applied = false;
foreach (var r in migration_rules) {
if (r.apply(settings, out var migrated)) {
settings = migrated;
applied = true;
}
}
new_settings = applied ? settings : default;
return applied;
}
public static void apply_quiet<T>(ref T settings, IEnumerable<ISettingsMigrationRule<T>> migration_rules) {
if (apply(settings, migration_rules, out var new_settings))
settings = new_settings;
}
public static ISettingsMigrationRule<T> merge<T>(this IEnumerable<ISettingsMigrationRule<T>> rules) =>
new MergeWrapper<T>(rules);
public static ISettingsMigrationRule<TOuter> wrap<TInner, TOuter>(this ISettingsMigrationRule<TInner> rule, IImmutableProperty<TOuter, TInner> propi) =>
new SelectorWrapper<TInner, TOuter>(rule, propi.get, propi.set);
public static ISettingsMigrationRule<TOuter> wrap<TInner, TOuter>(this ISettingsMigrationRule<TInner> rule, Func<TOuter, TInner> get, Func<TOuter, TInner, TOuter> set) =>
new SelectorWrapper<TInner, TOuter>(rule, get, set);
class MergeWrapper<T> : ISettingsMigrationRule<T> {
readonly IEnumerable<ISettingsMigrationRule<T>> _rules;
public MergeWrapper(IEnumerable<ISettingsMigrationRule<T>> rules) =>
_rules = rules;
public bool apply(T settings, out T new_settings) {
bool applied = false;
foreach (var r in _rules) {
if (r.apply(settings, out var migrated)) {
settings = migrated;
applied = true;
}
}
new_settings = applied ? settings : default;
return applied;
}
}
class SelectorWrapper<TInner, TOuter> : ISettingsMigrationRule<TOuter> {
readonly ISettingsMigrationRule<TInner> _rule;
readonly Func<TOuter, TInner> _get;
readonly Func<TOuter, TInner, TOuter> _set;
public SelectorWrapper(ISettingsMigrationRule<TInner> rule, Func<TOuter, TInner> get, Func<TOuter, TInner, TOuter> set) {
_rule = rule;
_get = get;
_set = set;
}
public bool apply(TOuter settings, out TOuter new_settings) {
if (settings != null) {
var ival = _get(settings);
if (_rule.apply(ival, out var new_ival)) {
new_settings = _set(settings, new_ival);
return true;
}
}
new_settings = default;
return false;
}
}
}
}
@@ -1,171 +1,152 @@
using mbts.spark;
using mbts.utils;
using System;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
namespace mbts.persist {
interface IWindowSettingsManager<T> where T : class {
T instance_settings { get; set; }
T default_settings { get; }
event Action<T> instance_settings_changed;
IObservable<T> subscribe_default();
Task save_default_settings(T value);
IWindowSettingsManagerNonShared<T> as_non_shared();
}
/// <summary>
/// An implementation of IWindowSettingsManager that uses a clone of the actual default settings;
/// provides a convenient way to avoid problems that arise from sharing a single default settings object among multiple window instances.
/// </summary>
interface IWindowSettingsManagerNonShared<T> : IWindowSettingsManager<T>, IDisposable where T : class { }
class WindowSettingsManager<T> : IWindowSettingsManager<T> where T : class {
readonly UserSettingsHub _hub;
readonly Func<UserSettings, T> _get;
readonly Func<UserSettings, T, UserSettings> _set;
T _instance_settings;
public WindowSettingsManager(UserSettingsHub hub, T instance_settings, Func<UserSettings, T> get, Func<UserSettings, T, UserSettings> set) {
_hub = hub;
_instance_settings = instance_settings;
_get = get;
_set = set;
}
public T instance_settings {
get => _instance_settings;
set {
_instance_settings = value;
instance_settings_changed?.Invoke(value);
}
}
public T default_settings => _get(_hub.current);
public event Action<T> instance_settings_changed;
public async Task save_default_settings(T value) =>
await _hub.save_default(_set(_hub.current, value));
public IObservable<T> subscribe_default() =>
_hub.subscribe_default_settings().Select(_get).DistinctUntilChanged();
public IWindowSettingsManagerNonShared<T> as_non_shared() =>
new NonSharedWrapper(this);
class NonSharedWrapper : IWindowSettingsManagerNonShared<T> {
readonly IWindowSettingsManager<T> _wsm;
readonly BehaviorSubject<T> _default_subject;
IDisposable _dispose;
public NonSharedWrapper(IWindowSettingsManager<T> wsm) {
_wsm = wsm;
_default_subject = new BehaviorSubject<T>(_wsm.default_settings);
_dispose = wsm.subscribe_default().Subscribe(s =>
_default_subject.OnNext(default_settings = MiscUtils.clone_proto(s)));
}
public T instance_settings {
get => _wsm.instance_settings;
set => _wsm.instance_settings = value;
}
public T default_settings { get; private set; }
public event Action<T> instance_settings_changed {
add => _wsm.instance_settings_changed += value;
remove => _wsm.instance_settings_changed -= value;
}
public async Task save_default_settings(T value) =>
await _wsm.save_default_settings(value);
public IObservable<T> subscribe_default() =>
_default_subject.AsObservable();
public IWindowSettingsManagerNonShared<T> as_non_shared() =>
new NonSharedWrapper(_wsm);
public void Dispose() => Disposable.dispose(ref _dispose);
}
public class DisconnectedImpl : IWindowSettingsManager<T> {
readonly BehaviorSubject<T> _default_settings_subject;
T _instance_settings, _default_settings;
public DisconnectedImpl(T settings) : this(settings, settings) { }
public DisconnectedImpl(T instance_settings, T default_settings) {
_instance_settings = instance_settings;
_default_settings = default_settings;
_default_settings_subject = new BehaviorSubject<T>(default_settings);
}
public T instance_settings {
get => _instance_settings;
set {
if (!Equals(_instance_settings, value)) {
_instance_settings = value;
instance_settings_changed?.Invoke(value);
}
}
}
public T default_settings {
get => _default_settings;
set {
if (!Equals(_default_settings, _default_settings)) {
_default_settings = value;
_default_settings_subject.OnNext(value);
}
}
}
public event Action<T> instance_settings_changed;
public IWindowSettingsManagerNonShared<T> as_non_shared() => new NonSharedWrapper(this);
public Task save_default_settings(T value) {
default_settings = value;
return Task.CompletedTask;
}
public IObservable<T> subscribe_default() => _default_settings_subject;
}
}
static class WindowSettingsManagerExtensions {
/// <summary>
/// Returns an observable sequence of the settings object used by a particular window.
/// <para/>Note: 'Instance' settings take priority over 'default' settings. While the former is present, any changes to the latter will be ignored.
/// </summary>
public static IObservable<T> subscribe_current<T>(this IWindowSettingsManager<T> wsm) where T : class =>
Observable.CombineLatest(
Observable.FromEvent<Action<T>, T>(cb => wsm.instance_settings_changed += cb, cb => wsm.instance_settings_changed -= cb)
.StartWith(wsm.instance_settings),
wsm.subscribe_default(),
(i, d) => i ?? d
).Where(v => v != null)
.DistinctUntilChanged();
public static IObservable<T> subscribe_current<T>(this IWindowSettingsManager<T> wsm, Func<(T defaults, T instance), T> merge_settings) where T : class, IDefaultableSettings {
return Observable.Create<T>(o => {
IDisposable defaults_sub = wsm.subscribe_default().Subscribe(_ => o.OnNext(get_current()));
wsm.instance_settings_changed += on_instance_settings_changed;
return Disposable.Create(() => {
defaults_sub.Dispose();
wsm.instance_settings_changed -= on_instance_settings_changed;
});
void on_instance_settings_changed(T _) =>
o.OnNext(get_current());
});
T get_current() {
var inst = wsm.instance_settings;
if (inst == null) return wsm.default_settings;
if (inst.use_defaults) return merge_settings((wsm.default_settings, inst));
return inst;
}
}
public static T current_settings<T>(this IWindowSettingsManager<T> wsm) where T : class =>
wsm.instance_settings ?? wsm.default_settings;
}
}
using mbts.spark;
using mbts.utils;
using System;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
namespace mbts.persist {
interface IWindowSettingsManager<T> where T : class {
T instance_settings { get; set; }
T default_settings { get; }
event Action<T> instance_settings_changed;
IObservable<T> subscribe_default();
Task save_default_settings(T value);
IWindowSettingsManagerNonShared<T> as_non_shared();
}
/// <summary>
/// An implementation of IWindowSettingsManager that uses a clone of the actual default settings;
/// provides a convenient way to avoid problems that arise from sharing a single default settings object among multiple window instances.
/// </summary>
interface IWindowSettingsManagerNonShared<T> : IWindowSettingsManager<T>, IDisposable where T : class { }
class WindowSettingsManager<T> : IWindowSettingsManager<T> where T : class {
readonly UserSettingsHub _hub;
readonly Func<UserSettings, T> _get;
readonly Func<UserSettings, T, UserSettings> _set;
T _instance_settings;
public WindowSettingsManager(UserSettingsHub hub, T instance_settings, Func<UserSettings, T> get, Func<UserSettings, T, UserSettings> set) {
_hub = hub;
_instance_settings = instance_settings;
_get = get;
_set = set;
}
public T instance_settings {
get => _instance_settings;
set {
_instance_settings = value;
instance_settings_changed?.Invoke(value);
}
}
public T default_settings => _get(_hub.current);
public event Action<T> instance_settings_changed;
public async Task save_default_settings(T value) =>
await _hub.save_default(_set(_hub.current, value));
public IObservable<T> subscribe_default() =>
_hub.subscribe_default_settings().Select(_get).DistinctUntilChanged();
public IWindowSettingsManagerNonShared<T> as_non_shared() =>
new NonSharedWrapper(this);
class NonSharedWrapper : IWindowSettingsManagerNonShared<T> {
readonly IWindowSettingsManager<T> _wsm;
readonly BehaviorSubject<T> _default_subject;
IDisposable _dispose;
public NonSharedWrapper(IWindowSettingsManager<T> wsm) {
_wsm = wsm;
_default_subject = new BehaviorSubject<T>(_wsm.default_settings);
_dispose = wsm.subscribe_default().Subscribe(s =>
_default_subject.OnNext(default_settings = MiscUtils.clone_proto(s)));
}
public T instance_settings {
get => _wsm.instance_settings;
set => _wsm.instance_settings = value;
}
public T default_settings { get; private set; }
public event Action<T> instance_settings_changed {
add => _wsm.instance_settings_changed += value;
remove => _wsm.instance_settings_changed -= value;
}
public async Task save_default_settings(T value) =>
await _wsm.save_default_settings(value);
public IObservable<T> subscribe_default() =>
_default_subject.AsObservable();
public IWindowSettingsManagerNonShared<T> as_non_shared() =>
new NonSharedWrapper(_wsm);
public void Dispose() => Disposable.dispose(ref _dispose);
}
public class DisconnectedImpl : IWindowSettingsManager<T> {
readonly BehaviorSubject<T> _default_settings_subject;
T _instance_settings, _default_settings;
public DisconnectedImpl(T settings) : this(settings, settings) { }
public DisconnectedImpl(T instance_settings, T default_settings) {
_instance_settings = instance_settings;
_default_settings = default_settings;
_default_settings_subject = new BehaviorSubject<T>(default_settings);
}
public T instance_settings {
get => _instance_settings;
set {
if (!Equals(_instance_settings, value)) {
_instance_settings = value;
instance_settings_changed?.Invoke(value);
}
}
}
public T default_settings {
get => _default_settings;
set {
if (!Equals(_default_settings, _default_settings)) {
_default_settings = value;
_default_settings_subject.OnNext(value);
}
}
}
public event Action<T> instance_settings_changed;
public IWindowSettingsManagerNonShared<T> as_non_shared() => new NonSharedWrapper(this);
public Task save_default_settings(T value) {
default_settings = value;
return Task.CompletedTask;
}
public IObservable<T> subscribe_default() => _default_settings_subject;
}
}
static class WindowSettingsManagerExtensions {
/// <summary>
/// Returns an observable sequence of the settings object used by a particular window.
/// <para/>Note: 'Instance' settings take priority over 'default' settings. While the former is present, any changes to the latter will be ignored.
/// </summary>
public static IObservable<T> subscribe_current<T>(this IWindowSettingsManager<T> wsm) where T : class =>
Observable.CombineLatest(
Observable.FromEvent<Action<T>, T>(cb => wsm.instance_settings_changed += cb, cb => wsm.instance_settings_changed -= cb)
.StartWith(wsm.instance_settings),
wsm.subscribe_default(),
(i, d) => i ?? d
).Where(v => v != null)
.DistinctUntilChanged();
public static T current_settings<T>(this IWindowSettingsManager<T> wsm) where T : class =>
wsm.instance_settings ?? wsm.default_settings;
}
}
@@ -0,0 +1,172 @@
#nullable enable
namespace mbts.persist {
using bts;
using bts.api.core;
using bts.api.persistence;
using bts.spark;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Reactive.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
public class SettingsPersistenceModel : IPersist, IUserPersist {
readonly PersistenceService _persist;
readonly ErrorReporter _errors;
readonly string _user;
public SettingsPersistenceModel(
string user, PersistenceService persist, ErrorReporter errors) {
_user = user;
_persist = persist;
_errors = errors;
}
public Task set<T>(string ns, string key, T value) {
return _persist.store_async(new StoreRequest() {
Ns = _user_ns(ns),
Record = {
new Record() {
Key = key,
Value = ProtobufSerializationHelper.serialize_to_byte_string(value)
}
}
});
}
public Task clear(string ns, string key) {
return _persist.remove_async(new RemoveRequest() {
Ns = _user_ns(ns),
Key = { key }
});
}
public async Task<T?> get<T>(string ns, string key) {
var ret = await _persist.retrieve_async(new RetrieveRequest() {
Ns = _user_ns(ns),
Key = { key }
});
_check_error(ret, ns, key, out var empty);
if (empty) {
return default;
}
return ProtobufSerializationHelper.deserialize<T>(ret.value.Record.Single().Value);
}
public async Task<T[]> get_many<T>(string ns, string key) {
var ret = await _persist.retrieve_async(new RetrieveRequest() {
Ns = _user_ns(ns),
Key = { key }
});
_check_error(ret, ns, key, out bool empty);
if (empty) {
return Array.Empty<T>();
}
return ProtobufSerializationHelper.deserialize_many<T>(
ret.value.Record.Single().Value.ToByteArray());
}
public async Task<IEnumerable<PersistResult<T>>> query<T>(string ns, string pattern) {
var regex = new Regex(pattern);
var results = await _persist.retrieve_all_async(
new RetrieveAllRequest() {
Ns = _user_ns(ns)
});
_check_error(results, ns, string.Empty, out bool empty);
if (empty) {
return Enumerable.Empty<PersistResult<T>>();
}
return results.value.Record
.Where(r => regex.IsMatch(r.Key))
.Select(r => new PersistResult<T>() {
user = _user,
ns = ns,
key = r.Key,
value = ProtobufSerializationHelper.deserialize<T>(r.Value)
}).ToList();
}
public IDisposable subscribe<T>(
string ns, string pattern, Action<IEnumerable<PersistResult<T>>> callback) =>
subscribe<T>(ns, pattern).Subscribe(callback);
public IObservable<IEnumerable<PersistResult<T>>> subscribe<T>(string ns, string pattern) {
var ctx = SynchronizationContext.Current ??
throw new InvalidOperationException("Current SynchronizationContext is null");
var re = new Regex(pattern);
return _persist
.subscribe_ns(_user_ns(ns))
.Select(update =>
update.added
.Where(item => re.IsMatch(item.Key))
.Select(item => new PersistResult<T>() {
user = _user,
ns = ns,
key = item.Key,
value = ProtobufSerializationHelper.deserialize<T>(item.Value)
}))
.SubscribeOn(ctx);
}
public void Dispose() =>
GC.SuppressFinalize(this);
string _user_ns(string ns) =>
$"{_user}#{ns}";
void _check_error(Result<RetrieveResponse> result, string ns, string key, out bool empty) {
if (result.success) {
switch (result.value.Result) {
case RetrieveResponse.Types.Result.EmptyNs:
case RetrieveResponse.Types.Result.NoSuchNs:
case RetrieveResponse.Types.Result.NoSuchKey:
empty = true;
return;
case RetrieveResponse.Types.Result.EmptyKey:
case RetrieveResponse.Types.Result.DuplicateKey:
_errors?.report_error(
$"Invalid Key {result} '{key}'",
"Requested Invalid Settings Key",
MessageBoxImage.Information);
empty = true;
return;
default:
case RetrieveResponse.Types.Result.Ok:
empty = false;
return;
}
} else {
_errors?.report_error(
$"There was an error communicating with the settings server: {result.error_message}",
"Failed to retrieve settings from the server");
empty = true;
}
}
}
[Export(typeof(IPersist))]
public class UISettings : SettingsPersistenceModel {
[ImportingConstructor]
public UISettings([Import("settings")] PersistenceService persist, ErrorReporter err)
: base("all_users", persist, err) { }
}
[Export(typeof(IUserPersist))]
public class UserUISettings : SettingsPersistenceModel {
public UserUISettings(
uint user_id, [Import("settings")] PersistenceService persist, ErrorReporter err)
: base($"User {user_id}", persist, err) { }
[ImportingConstructor]
public UserUISettings(
Lazy<UserTuple> user, [Import("settings")] PersistenceService persist, ErrorReporter err)
: this(user.Value.id, persist, err) { }
}
}
@@ -0,0 +1,44 @@
#nullable enable
namespace mbts.spark {
using bts.utils;
using System;
interface ISettingsProfile<T> {
uint id { get; }
string? name { get; }
T? value { get; }
SecurityCriteria? security_criteria { get; }
}
readonly struct SettingsProfile<T> : IEquatable<SettingsProfile<T>> where T : class, IEquatable<T> {
public static readonly Func<SettingsProfile<T>, uint> key_fn = ns => ns.id;
public readonly uint id;
public readonly string? name;
public readonly T? value;
public readonly SecurityCriteria? security_criteria;
public SettingsProfile(uint id, string? name, T? value, SecurityCriteria? security_criteria = null) {
this.id = id;
this.name = name;
this.value = value;
this.security_criteria = security_criteria;
}
public SettingsProfile<T> with(uint? id = null, string? name = null, T? value = null, SecurityCriteria? security_criteria = null) =>
new(id ?? this.id, name ?? this.name, value ?? this.value, security_criteria ?? this.security_criteria);
public bool Equals(SettingsProfile<T> other) =>
id == other.id &&
name == other.name &&
value.safe_equals(other.value) &&
security_criteria.safe_equals(other.security_criteria);
public override bool Equals(object? obj) =>
obj is SettingsProfile<T> other && Equals(other);
public override int GetHashCode() =>
id.GetHashCode();
}
}
@@ -1,63 +1,73 @@
using mbts.persist;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace mbts.ui.tests {
// Stub persistance store for shell unit tests
public class TestPersist : IPersist, IUserPersist {
public Dictionary<string, Dictionary<string, object>> Values = new Dictionary<string, Dictionary<string, object>>();
public Task set<T>(string ns, string key, T value) {
TaskCompletionSource<object> source = new TaskCompletionSource<object>();
try {
Values[ns][key] = value;
source.TrySetResult(null);
} catch (Exception e) {
source.TrySetException(e);
}
return source.Task;
}
public Task clear(string ns, string key) {
TaskCompletionSource<object> source = new TaskCompletionSource<object>();
try {
Values[ns].Remove(key);
source.TrySetResult(null);
} catch (Exception e) {
source.TrySetException(e);
}
return source.Task;
}
public Task<T> get<T>(string ns, string key) {
TaskCompletionSource<T> source = new TaskCompletionSource<T>();
try {
T result = (T)Values[ns][key];
source.TrySetResult(result);
} catch (Exception e) {
source.TrySetException(e);
}
return source.Task;
}
public async Task<IEnumerable<Tuple<T, DateTime>>> get_history<T>(string ns, string key) {
var res = await get<T>(ns, key);
return new Tuple<T, DateTime>[] { Tuple.Create(res, DateTime.Today) };
}
public Task<IEnumerable<PersistResult<T>>> query<T>(string ns, string pattern) {
throw new NotImplementedException();
}
public IDisposable subscribe<T>(string ns, string pattern, Action<IEnumerable<PersistResult<T>>> callback) {
throw new NotImplementedException();
}
public void Dispose() { }
}
}
using mbts.persist;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace mbts.ui.tests {
// Stub persistance store for shell unit tests
public class TestPersist : IPersist, IUserPersist {
public Dictionary<string, Dictionary<string, object>> Values = new Dictionary<string, Dictionary<string, object>>();
public Task set<T>(string ns, string key, T value) {
TaskCompletionSource<object> source = new TaskCompletionSource<object>();
try {
Values[ns][key] = value;
source.TrySetResult(null);
} catch (Exception e) {
source.TrySetException(e);
}
return source.Task;
}
public Task clear(string ns, string key) {
TaskCompletionSource<object> source = new TaskCompletionSource<object>();
try {
Values[ns].Remove(key);
source.TrySetResult(null);
} catch (Exception e) {
source.TrySetException(e);
}
return source.Task;
}
public Task<T> get<T>(string ns, string key) {
TaskCompletionSource<T> source = new TaskCompletionSource<T>();
try {
T result = (T)Values[ns][key];
source.TrySetResult(result);
} catch (Exception e) {
source.TrySetException(e);
}
return source.Task;
}
public Task<T[]> get_many<T>(string ns, string key) {
var source = new TaskCompletionSource<T[]>();
try {
source.TrySetResult((T[])Values[ns][key]);
} catch (Exception e) {
source.TrySetException(e);
}
return source.Task;
}
public async Task<IEnumerable<Tuple<T, DateTime>>> get_history<T>(string ns, string key) {
var res = await get<T>(ns, key);
return new Tuple<T, DateTime>[] { Tuple.Create(res, DateTime.Today) };
}
public Task<IEnumerable<PersistResult<T>>> query<T>(string ns, string pattern) {
throw new NotImplementedException();
}
public IDisposable subscribe<T>(string ns, string pattern, Action<IEnumerable<PersistResult<T>>> callback) {
throw new NotImplementedException();
}
public void Dispose() { }
}
}
@@ -1,189 +1,232 @@
using bts.shell.pnl;
using Google.Protobuf.WellKnownTypes;
using mbts.ui.settings;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Linq;
namespace mbts.spark {
interface IDefaultableSettings {
bool use_defaults { get; set; }
}
/// <summary>
/// The settings Mothership. All window - and any other future user based - settings should have a corresponding default member here.
/// </summary>
[ProtoContract]
class UserSettings {
public static UserSettings factory_defaults =>
new UserSettings {
_ladder = LadderSettings.Default,
_notification = NotificationSettings.Default,
_market_view_grid = bts.shell.market_view.MarketViewSettings.DefaultGridSettings,
_fills_grid = bts.shell.fills.FillsSettings.DefaultGridSettings,
_time_and_sales_grid = bts.shell.time_and_sales.TimeAndSalesSettings.DefaultGridSettings,
_synthetic_management_grid = bts.shell.SyntheticManagementWindowFactory.StartupData.DefaultGridSettings,
_order_book_grid = bts.shell.orderbook.OrderBookStartupData.DefaultGrid
};
[ProtoMember(1)]
LadderSettings _ladder;
[ProtoMember(11)]
readonly LadderSettingsProfile[] _ladder_profiles;
/// When Profiles Are Deleted, ladders that were using that profile shall copy the profile's settings to a local profile.
/// Therefor:
/// Deleted profile ids must never be reused.
/// If they were reused, consider an unloaded workspace with ladders that were using the deleted profile.
/// If such a workspace was reloaded after a new profile was saved with the deleted one's id, the ladders using that deleted profile would suddenly be using the new profile.
/// To Prevent IDs From Being Recycled:
/// The last profile id is stored in the protobuf (<see cref="_last_ladder_profile_id"/>).
/// Anytime a profile is added, it shall use <see cref="next_ladder_profile_id"/>.
[ProtoMember(12)]
uint _last_ladder_profile_id;
// removing NotificationSettings these from proto-serialization, since they are disabled by default for now.
// This way, when they are enabled, there won't be any backwards compatability issues to worry about, as no clients will have persisted them yet.
NotificationSettings _notification;
[ProtoMember(5)]
GridSettings _market_view_grid;
[ProtoMember(6)]
GridSettings _time_and_sales_grid;
[ProtoMember(7)]
GridSettings _fills_grid;
[ProtoMember(8)]
GridSettings _synthetic_management_grid;
[ProtoMember(9)]
bts.shell.orderbook.OrderBookGridSettings _order_book_grid;
[ProtoMember(10)]
PNLSettings _pnl;
[ProtoMember(13)]
GlobalAlertSettings _alerts;
public UserSettings() { }
public UserSettings(LadderSettingsProfile[] ladder_profiles) =>
_ladder_profiles = ladder_profiles;
public LadderSettings ladder => _ladder ?? (_ladder = LadderSettings.Default);
public IReadOnlyList<LadderSettingsProfile> ladder_profiles => _ladder_profiles ?? Array.Empty<LadderSettingsProfile>();
public uint next_ladder_profile_id => _last_ladder_profile_id + 1;
public NotificationSettings notification => _notification ?? (_notification = NotificationSettings.Default);
public GridSettings market_view_grid => _market_view_grid ?? (_market_view_grid = bts.shell.market_view.MarketViewSettings.DefaultGridSettings);
public GridSettings time_and_sales_grid => _time_and_sales_grid ?? (_time_and_sales_grid = GridSettings.Default.with(bts.shell.time_and_sales.TimeAndSalesSettings.DefaultColumns.all));
public GridSettings fills_grid => _fills_grid ?? (_fills_grid = bts.shell.fills.FillsSettings.DefaultGridSettings);
public GridSettings synthetic_management_grid => _synthetic_management_grid ?? (_synthetic_management_grid = bts.shell.SyntheticManagementWindowFactory.StartupData.DefaultGridSettings);
public PNLSettings pnl => _pnl ?? (_pnl = PNLSettings.Default);
public bts.shell.orderbook.OrderBookGridSettings order_book_grid => _order_book_grid ?? (_order_book_grid = bts.shell.orderbook.OrderBookStartupData.Default.grid_settings_wrapper());
public GlobalAlertSettings alerts => _alerts ?? (_alerts = new GlobalAlertSettings());
public UserSettings with(LadderSettings ladder = null,
LadderSettingsProfile[] ladder_profiles = null,
NotificationSettings notification = null,
GridSettings provided_market_view_gridsettings = null,
GridSettings time_and_sales = null,
GridSettings provided_fills_gridsettings = null,
GridSettings provided_synthetic_management_gridsettings = null,
PNLSettings pnl = null,
bts.shell.orderbook.OrderBookGridSettings order_book_grid = null,
GlobalAlertSettings alerts = null) {
var us = new UserSettings(ladder_profiles ?? _ladder_profiles) {
_ladder = ladder ?? _ladder,
_notification = notification ?? _notification,
_market_view_grid = provided_market_view_gridsettings ?? _market_view_grid,
_time_and_sales_grid = time_and_sales ?? _time_and_sales_grid,
_fills_grid = provided_fills_gridsettings ?? _fills_grid,
_synthetic_management_grid = provided_synthetic_management_gridsettings ?? _synthetic_management_grid,
_pnl = pnl ?? _pnl,
_order_book_grid = order_book_grid ?? _order_book_grid,
_alerts = alerts ?? _alerts
};
us._last_ladder_profile_id = Math.Max(_last_ladder_profile_id, us.ladder_profiles.Select(p => p.id).MaxOrDefault());
return us;
}
public static class FileExtensions {
public const string
GRID = "grid",
LADDER = "ladder",
PNL = "pnl";
}
}
// - currently all notification-triggers are in GridSettings
// - the SoundNotificationSettings below are used to disable/enable SoundNotifications
// - the ToastNotificationSettings below are used to disable/enable ToastNotifications, and adjust the flash-duration (if enabled).
// - since this is a new feature, the ability to quickly enable/disable both types of notifications may save us the trouble of having to redeploy,
// in the unfortunate event that a bug slipped through the cracks, or the performance impact is more significant than expected.
// TODO: maybe globalize notification settings?
[ProtoContract]
class NotificationSettings {
[ProtoMember(1)]
readonly SoundNotificationSettings _sound_notification;
[ProtoMember(2)]
readonly ToastNotificationSettings _toast_notification;
public NotificationSettings() { }
public NotificationSettings(SoundNotificationSettings sound_notification, ToastNotificationSettings toast_notification) {
_sound_notification = sound_notification;
_toast_notification = toast_notification;
}
public static NotificationSettings Default => new NotificationSettings(SoundNotificationSettings.Default, ToastNotificationSettings.Default);
public SoundNotificationSettings sound_notification => _sound_notification;
public ToastNotificationSettings toast_notification => _toast_notification;
}
[ProtoContract]
class SoundNotificationSettings {
[ProtoMember(1)]
readonly bool _enabled;
public SoundNotificationSettings() { }
public SoundNotificationSettings(bool enabled) =>
_enabled = enabled;
public static SoundNotificationSettings Default => new SoundNotificationSettings(true);
public bool enabled => _enabled;
}
[ProtoContract]
class ToastNotificationSettings {
// though it is possible to infer such Modes from Duration values (null = Disabled, max = ManualClose, otherwise Flash)
// this Mode enum makes the behavior very clear, and less likely to be misinterpretted down the road.
// (without this enum, the meaning of "duration = null," and "duration = 0 seconds," is debatable)
public enum Mode {
Disabled,
ManualClose,
Flash
}
public static ToastNotificationSettings Default =>
new ToastNotificationSettings(Mode.Flash, new Duration { Seconds = 5 }, 320);
[ProtoMember(1)]
readonly Mode _mode;
[ProtoMember(2)]
readonly Duration _duration;
[ProtoMember(3)]
readonly double _max_height;
public ToastNotificationSettings() { }
public ToastNotificationSettings(Mode mode, Duration duration, double max_height) {
_mode = mode;
_duration = duration;
_max_height = max_height;
}
public Mode mode => _mode;
public TimeSpan? duration => _mode == Mode.Flash ? _duration?.ToTimeSpan() ?? TimeSpan.FromSeconds(5) : new TimeSpan?();
public double max_height => _max_height;
}
}
#nullable enable
namespace mbts.spark {
using bts.shell;
using bts.shell.fills;
using bts.shell.market_view;
using bts.shell.orderbook;
using bts.shell.pnl;
using bts.shell.time_and_sales;
using Google.Protobuf.WellKnownTypes;
using mbts.ui.settings;
using ProtoBuf;
using Spark.Trading;
using System;
using System.Collections.Generic;
using System.Linq;
interface IDefaultableSettings {
bool use_defaults { get; set; }
}
/// <summary>
/// The settings Mothership. All window - and any other future user based - settings should have a corresponding default member here.
/// </summary>
[ProtoContract]
class UserSettings {
public static UserSettings factory_defaults =>
new() {
_ladder = LadderSettings.Default,
_notification = NotificationSettings.Default,
_market_view_grid = MarketViewSettings.DefaultGridSettings,
_fills_grid = FillsSettings.DefaultGridSettings,
_time_and_sales_grid = TimeAndSalesSettings.DefaultGridSettings,
_synthetic_management = SyntheticManagementSettings.default_grid_settings,
_reconcile_report = ReconcileReportSettings.Default().grid,
_order_book = OrderBookStartupData.DefaultGrid
};
[ProtoMember(1)]
LadderSettings? _ladder;
[ProtoMember(11)]
LadderSettingsProfile[]? _ladder_profiles;
/// When Profiles Are Deleted, ladders that were using that profile shall copy the profile's settings to a local profile.
/// Therefor:
/// Deleted profile ids must never be reused.
/// If they were reused, consider an unloaded workspace with ladders that were using the deleted profile.
/// If such a workspace was reloaded after a new profile was saved with the deleted one's id, the ladders using that deleted profile would suddenly be using the new profile.
/// To Prevent IDs From Being Recycled:
/// The last profile id is stored in the protobuf (<see cref="_last_ladder_profile_id"/>).
/// Anytime a profile is added, it shall use <see cref="next_ladder_profile_id"/>.
[ProtoMember(12)]
uint _last_ladder_profile_id;
// removing NotificationSettings these from proto-serialization, since they are disabled by default for now.
// This way, when they are enabled, there won't be any backwards compatability issues to worry about, as no clients will have persisted them yet.
NotificationSettings? _notification;
[ProtoMember(5)]
GridSettings? _market_view_grid;
[ProtoMember(6)]
GridSettings? _time_and_sales_grid;
[ProtoMember(7)]
GridSettings? _fills_grid;
[ProtoMember(8)]
GridSettings? _synthetic_management;
[ProtoMember(14)]
GridSettings? _reconcile_report;
[ProtoMember(9)]
OrderBookGridSettings? _order_book;
[ProtoMember(10)]
PNLSettings? _pnl;
[ProtoMember(13)]
GlobalAlertSettings? _alerts;
public UserSettings() { }
public LadderSettings ladder =>
_ladder ??= LadderSettings.Default;
public IReadOnlyList<LadderSettingsProfile> ladder_profiles =>
_ladder_profiles ?? Array.Empty<LadderSettingsProfile>();
public uint next_ladder_profile_id =>
_last_ladder_profile_id + 1;
public NotificationSettings notification =>
_notification ??= NotificationSettings.Default;
public GridSettings market_view_grid =>
_market_view_grid ??= MarketViewSettings.DefaultGridSettings;
public GridSettings time_and_sales_grid =>
_time_and_sales_grid ??= GridSettings.Default.with(
TimeAndSalesSettings.DefaultColumns.all);
public GridSettings fills_grid =>
_fills_grid ??= FillsSettings.DefaultGridSettings;
public GridSettings synthetic_management_grid =>
_synthetic_management ??=
SyntheticManagementSettings.default_grid_settings;
public GridSettings reconcile_report_grid =>
_reconcile_report ??= ReconcileReportSettings.Default().grid ??
throw new InvalidOperationException();
public PNLSettings pnl =>
_pnl ??= PNLSettings.Default;
public OrderBookGridSettings order_book_grid =>
_order_book ??= OrderBookStartupData.Default.grid_settings_wrapper();
public GlobalAlertSettings alerts =>
_alerts ??= new GlobalAlertSettings();
public UserSettings with(
LadderSettings? ladder = null,
LadderSettingsProfile[]? ladder_profiles = null,
NotificationSettings? notification = null,
GridSettings? market_view = null,
GridSettings? time_and_sales = null,
GridSettings? fills = null,
GridSettings? synthetic_management = null,
GridSettings? reconcile_report = null,
PNLSettings? pnl = null,
OrderBookGridSettings? order_book_grid = null,
GlobalAlertSettings? alerts = null) {
var us = new UserSettings() {
_ladder_profiles = ladder_profiles ?? _ladder_profiles,
_ladder = ladder ?? _ladder,
_notification = notification ?? _notification,
_market_view_grid = market_view ?? _market_view_grid,
_time_and_sales_grid = time_and_sales ?? _time_and_sales_grid,
_fills_grid = fills ?? _fills_grid,
_synthetic_management = synthetic_management ?? _synthetic_management,
_reconcile_report = reconcile_report ?? _reconcile_report,
_pnl = pnl ?? _pnl,
_order_book = order_book_grid ?? _order_book,
_alerts = alerts ?? _alerts
};
us._last_ladder_profile_id = Math.Max(_last_ladder_profile_id, us.ladder_profiles.Select(p => p.id).MaxOrDefault());
return us;
}
public static class FileExtensions {
public const string
GRID = "grid",
LADDER = "ladder",
PNL = "pnl";
}
}
// - currently all notification-triggers are in GridSettings
// - the SoundNotificationSettings below are used to disable/enable SoundNotifications
// - the ToastNotificationSettings below are used to disable/enable ToastNotifications, and adjust the flash-duration (if enabled).
// - since this is a new feature, the ability to quickly enable/disable both types of notifications may save us the trouble of having to redeploy,
// in the unfortunate event that a bug slipped through the cracks, or the performance impact is more significant than expected.
// TODO: maybe globalize notification settings?
[ProtoContract]
class NotificationSettings {
[ProtoMember(1)]
readonly SoundNotificationSettings? _sound_notification;
[ProtoMember(2)]
readonly ToastNotificationSettings? _toast_notification;
public NotificationSettings() { }
public NotificationSettings(SoundNotificationSettings sound_notification, ToastNotificationSettings toast_notification) {
_sound_notification = sound_notification;
_toast_notification = toast_notification;
}
public static NotificationSettings Default => new NotificationSettings(SoundNotificationSettings.Default, ToastNotificationSettings.Default);
public SoundNotificationSettings? sound_notification => _sound_notification;
public ToastNotificationSettings? toast_notification => _toast_notification;
}
[ProtoContract]
class SoundNotificationSettings {
[ProtoMember(1)]
readonly bool _enabled;
public SoundNotificationSettings() { }
public SoundNotificationSettings(bool enabled) =>
_enabled = enabled;
public static SoundNotificationSettings Default => new(true);
public bool enabled => _enabled;
}
[ProtoContract]
class ToastNotificationSettings {
// though it is possible to infer such Modes from Duration values (null = Disabled, max = ManualClose, otherwise Flash)
// this Mode enum makes the behavior very clear, and less likely to be misinterpretted down the road.
// (without this enum, the meaning of "duration = null," and "duration = 0 seconds," is debatable)
public enum Mode {
Disabled,
ManualClose,
Flash
}
public static ToastNotificationSettings Default =>
new(Mode.Flash, new Duration { Seconds = 5 }, 320);
[ProtoMember(1)]
readonly Mode _mode;
[ProtoMember(2)]
readonly Duration? _duration;
[ProtoMember(3)]
readonly double _max_height;
public ToastNotificationSettings() { }
public ToastNotificationSettings(Mode mode, Duration duration, double max_height) {
_mode = mode;
_duration = duration;
_max_height = max_height;
}
public Mode mode => _mode;
public TimeSpan duration =>
_mode switch {
Mode.Flash => _duration?.ToTimeSpan() ?? TimeSpan.FromSeconds(5),
_ => new()
};
public double max_height => _max_height;
}
}
@@ -0,0 +1,41 @@
#nullable enable
namespace mbts.spark {
using bts;
using bts.api;
using mbts.persist;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
static class UserSettingsExtensions {
/// <summary>
/// Gets the ladder settings profile for a particular security
/// </summary>
public static LadderSettingsProfile? get_ladder_profile(
this UserSettings settings, SecurityImmutable security) =>
settings.ladder_profiles.FirstOrDefault(lsp =>
lsp?.security_criteria?.includes(security) ?? false);
public static IObservable<LadderSettingsProfile?> subscribe_ladder_profile(
this UserSettingsHub settings_hub, SecurityImmutable security) =>
settings_hub.subscribe_default_settings().Select(s =>
s.get_ladder_profile(security));
/// <summary>
/// Gets the default account for a particular security (from the
/// <see cref="LadderSettingsProfile"/> associated with that security)
/// </summary>
public static IObservable<AccountTuple?> subscribe_default_account(
this UserSettingsHub settings_hub, IBus bus, SecurityImmutable security) {
var acc_id_src = settings_hub.subscribe_default_settings().Select(s =>
s.get_ladder_profile(security)?.value?.default_account);
return acc_id_src.CombineLatest(
bus.subscribe(SparkTags.AccountsTag),
(acc_id, accs) => acc_id.HasValue && accs.TryGetValue(acc_id.Value, out var acc_tup) ?
acc_tup : (AccountTuple?)null);
}
}
}
@@ -1,165 +1,177 @@
using bts;
using bts.settings;
using bts.shell.pnl;
using bts.utils;
using mbts.spark;
using mbts.ui.settings;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
namespace mbts.persist {
/// <summary>
/// Represents the top level of the persisted settings hierarchy.
/// One UserSettings object, which contains the defaults for every SparkWindow, can be read/written on the server by UISettingsHub.
/// </summary>
[Export(typeof(UserSettingsHub))]
class UserSettingsHub {
// do NOT CHANGE these consts, they represent a file path on the server
const string NAME_SPACE = "settings", DEFAULT_KEY = "default";
static readonly IImmutableProperty<UserSettings, GridSettings>
_fills_propi = ImmutableProperty.create<UserSettings, GridSettings>(us => us.fills_grid, (us, gs) => us.with(provided_fills_gridsettings: gs)),
_mview_propi = ImmutableProperty.create<UserSettings, GridSettings>(us => us.market_view_grid, (us, gs) => us.with(provided_market_view_gridsettings: gs)),
_synth_propi = ImmutableProperty.create<UserSettings, GridSettings>(us => us.synthetic_management_grid, (us, gs) => us.with(provided_synthetic_management_gridsettings: gs));
static readonly IImmutableProperty<UserSettings, PNLSettings>
_pnl_propi = ImmutableProperty.create<UserSettings, PNLSettings>(us => us.pnl, (us, pnl) => us.with(pnl: pnl));
readonly object _default_settings_lock = new object();
readonly BehaviorSubject<UserSettings> _default_settings_subject = new BehaviorSubject<UserSettings>(UserSettings.factory_defaults);
readonly IEnumerable<IFillsGridSettingsMigrationRule> _fills_migration_rules;
readonly IEnumerable<IMarketViewGridSettingsMigrationRule> _mview_migration_rules;
readonly IEnumerable<IPNLSettingsMigrationRule> _pnl_migration_rules;
readonly IEnumerable<ISyntheticManagementMigrationRule> _synth_migration_rules;
readonly IUserPersist _persist;
UserSettings _default_settings;
[ImportingConstructor]
public UserSettingsHub(
IUserPersist persist,
[ImportMany] IEnumerable<IFillsGridSettingsMigrationRule> fills_migration_rules,
[ImportMany] IEnumerable<IMarketViewGridSettingsMigrationRule> mview_migration_rules,
[ImportMany] IEnumerable<IPAndLGridSettingsMigrationRule> pandl_migration_rules,
[ImportMany] IEnumerable<IPNLSettingsMigrationRule> pnl_migration_rules,
[ImportMany] IEnumerable<ISyntheticManagementMigrationRule> synth_migration_rules) {
//
_persist = persist;
_fills_migration_rules = fills_migration_rules ?? Enumerable.Empty<IFillsGridSettingsMigrationRule>();
_mview_migration_rules = mview_migration_rules ?? Enumerable.Empty<IMarketViewGridSettingsMigrationRule>();
_pnl_migration_rules = pnl_migration_rules ?? Enumerable.Empty<IPNLSettingsMigrationRule>();
_synth_migration_rules = synth_migration_rules ?? Enumerable.Empty<ISyntheticManagementMigrationRule>();
init();
async void init() {
UserSettings s;
try {
s = await _persist.get<UserSettings>(NAME_SPACE, DEFAULT_KEY);
if (s != null) {
var wrapped_rules = new[] {
_fills_migration_rules.merge().wrap(_fills_propi),
_mview_migration_rules.merge().wrap(_mview_propi),
_pnl_migration_rules.merge().wrap(_pnl_propi),
_synth_migration_rules.merge().wrap(_synth_propi)
};
SettingsMigrationHelper.apply_quiet(ref s, wrapped_rules);
// TODO: move ladder sanitization logic into ISettingsMigrationRule
s.ladder.sanitize();
// ensure valid named ladder set (w/ distinct, non-zero ids)
var ladder_profile_map = new Dictionary<uint, LadderSettingsProfile>();
var unidentified_lps = new List<LadderSettingsProfile>();
foreach (var lp in s.ladder_profiles) {
lp.value.sanitize();
if (lp.id == 0) {
unidentified_lps.Add(lp);
} else ladder_profile_map[lp.id] = lp;
}
uint id = s.next_ladder_profile_id;
foreach (var lp in unidentified_lps) {
ladder_profile_map[id] = lp.with(id);
id++;
}
var sorted_lps = ladder_profile_map.Values.ToArray();
Array.Sort(sorted_lps, Comparer<uint>.Default.wrap<uint, LadderSettingsProfile>(lp => lp.id));
if (!sorted_lps.SequenceEqual(s.ladder_profiles))
await _persist.set(NAME_SPACE, DEFAULT_KEY, s = s.with(ladder_profiles: sorted_lps));
}
} catch (Exception ex) {
Log.Persist.warn($"Error loading {typeof(UserSettings)} from namespace '{NAME_SPACE}', will restore factory defaults and continue as usual: {ex}");
await save_default(s = UserSettings.factory_defaults);
}
lock (_default_settings_lock) {
initialized = true;
if (s != null)
_default_settings_subject.OnNext(_default_settings = s);
}
}
}
// indicates whether or not the settings have been loaded from the server (this happens once, on startup - see the constructor for details)
public bool initialized { get; private set; }
internal UserSettings current {
get {
lock (_default_settings_lock)
return _default_settings ?? UserSettings.factory_defaults;
}
}
/// Subscribing via _persist.subscribe may be cleaner in theory, however using a local event allows observers to be notified immediately.
/// Assuming there aren't any rogue agents saving UserSettings by themselves, there should never be any discrepancies.
public IObservable<UserSettings> subscribe_default_settings() => _default_settings_subject.AsObservable();
public IWindowSettingsManager<GridSettings> create_fills_settings_manager(GridSettings instance_settings) =>
_create_settings_manager(
instance_settings,
_fills_migration_rules,
_fills_propi);
public IWindowSettingsManager<GridSettings> create_mview_settings_manager(GridSettings instance_settings) =>
_create_settings_manager(
instance_settings,
_mview_migration_rules,
_mview_propi);
public IWindowSettingsManager<PNLSettings> create_pnl_settings_manager(PNLSettings instance_settings) =>
_create_settings_manager(
instance_settings,
_pnl_migration_rules,
_pnl_propi);
public IWindowSettingsManager<GridSettings> create_synth_settings_manager(GridSettings instance_settings) =>
_create_settings_manager(
instance_settings,
_synth_migration_rules,
_synth_propi);
public async Task save_default(UserSettings value) {
// notify observers before persisting so the changes are reflected immediately in the ui
lock (_default_settings_lock) {
_default_settings_subject.OnNext(_default_settings = value);
}
await _persist_async();
}
IWindowSettingsManager<T> _create_settings_manager<T>(T instance_settings, IEnumerable<ISettingsMigrationRule<T>> migration_rules, IImmutableProperty<UserSettings, T> propi) where T : class {
if (instance_settings != null && migration_rules.merge().apply(instance_settings, out var new_settings))
instance_settings = new_settings;
return new WindowSettingsManager<T>(this, instance_settings, propi.get, propi.set);
}
async Task _persist_async() {
try {
await _persist.set(NAME_SPACE, DEFAULT_KEY, _default_settings);
} catch (Exception ex) {
Log.Persist.warn($"Error persisting {typeof(UserSettings)} in namespace '{NAME_SPACE}': {ex}");
}
}
}
}
using bts;
using bts.settings;
using bts.shell.pnl;
using bts.utils;
using mbts.spark;
using mbts.ui.settings;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
namespace mbts.persist {
/// <summary>
/// Represents the top level of the persisted settings hierarchy.
/// One UserSettings object, which contains the defaults for every SparkWindow, can be read/written on the server by UISettingsHub.
/// </summary>
[Export(typeof(UserSettingsHub))]
class UserSettingsHub {
// do NOT CHANGE these consts, they represent a file path on the server
const string NAME_SPACE = "settings", DEFAULT_KEY = "default";
static readonly IImmutableProperty<UserSettings, GridSettings>
_fills_propi = ImmutableProperty.create<UserSettings, GridSettings>(us => us.fills_grid, (us, gs) => us.with(fills: gs)),
_mview_propi = ImmutableProperty.create<UserSettings, GridSettings>(us => us.market_view_grid, (us, gs) => us.with(market_view: gs)),
_synth_propi = ImmutableProperty.create<UserSettings, GridSettings>(us => us.synthetic_management_grid, (us, gs) => us.with(synthetic_management: gs)),
_reconcile_report_propi = ImmutableProperty.create<UserSettings, GridSettings>(us => us.reconcile_report_grid, (us, gs) => us.with(reconcile_report: gs));
static readonly IImmutableProperty<UserSettings, PNLSettings>
_pnl_propi = ImmutableProperty.create<UserSettings, PNLSettings>(us => us.pnl, (us, pnl) => us.with(pnl: pnl));
readonly object _default_settings_lock = new object();
readonly BehaviorSubject<UserSettings> _default_settings_subject = new BehaviorSubject<UserSettings>(UserSettings.factory_defaults);
readonly IEnumerable<IFillsGridSettingsMigrationRule> _fills_migration_rules;
readonly IEnumerable<IMarketViewGridSettingsMigrationRule> _mview_migration_rules;
readonly IEnumerable<IPNLSettingsMigrationRule> _pnl_migration_rules;
readonly IEnumerable<ISyntheticManagementMigrationRule> _synth_migration_rules;
readonly IEnumerable<IReconcileReportMigrationRule> _reconcile_report_migration_rules;
readonly IUserPersist _persist;
UserSettings _default_settings;
[ImportingConstructor]
public UserSettingsHub(
IUserPersist persist,
[ImportMany] IEnumerable<IFillsGridSettingsMigrationRule> fills_migration_rules,
[ImportMany] IEnumerable<IMarketViewGridSettingsMigrationRule> mview_migration_rules,
[ImportMany] IEnumerable<IPAndLGridSettingsMigrationRule> pandl_migration_rules,
[ImportMany] IEnumerable<IPNLSettingsMigrationRule> pnl_migration_rules,
[ImportMany] IEnumerable<ISyntheticManagementMigrationRule> synth_migration_rules,
[ImportMany] IEnumerable<IReconcileReportMigrationRule> reconcile_report_migration_rules) {
//
_persist = persist;
_fills_migration_rules = fills_migration_rules ?? Enumerable.Empty<IFillsGridSettingsMigrationRule>();
_mview_migration_rules = mview_migration_rules ?? Enumerable.Empty<IMarketViewGridSettingsMigrationRule>();
_pnl_migration_rules = pnl_migration_rules ?? Enumerable.Empty<IPNLSettingsMigrationRule>();
_synth_migration_rules = synth_migration_rules ?? Enumerable.Empty<ISyntheticManagementMigrationRule>();
_reconcile_report_migration_rules = reconcile_report_migration_rules.empty_if_null();
init();
async void init() {
UserSettings s;
try {
s = await _persist.get<UserSettings>(NAME_SPACE, DEFAULT_KEY);
if (s != null) {
var wrapped_rules = new[] {
_fills_migration_rules.merge().wrap(_fills_propi),
_mview_migration_rules.merge().wrap(_mview_propi),
_pnl_migration_rules.merge().wrap(_pnl_propi),
_synth_migration_rules.merge().wrap(_synth_propi),
_reconcile_report_migration_rules.merge().wrap(_reconcile_report_propi)
};
SettingsMigrationHelper.apply_quiet(ref s, wrapped_rules);
// TODO: move ladder sanitization logic into ISettingsMigrationRule
s.ladder.sanitize();
// ensure valid named ladder set (w/ distinct, non-zero ids)
var ladder_profile_map = new Dictionary<uint, LadderSettingsProfile>();
var unidentified_lps = new List<LadderSettingsProfile>();
foreach (var lp in s.ladder_profiles) {
lp.value.sanitize();
if (lp.id == 0) {
unidentified_lps.Add(lp);
} else ladder_profile_map[lp.id] = lp;
}
uint id = s.next_ladder_profile_id;
foreach (var lp in unidentified_lps) {
ladder_profile_map[id] = lp.with(id);
id++;
}
var sorted_lps = ladder_profile_map.Values.ToArray();
Array.Sort(sorted_lps, Comparer<uint>.Default.wrap<uint, LadderSettingsProfile>(lp => lp.id));
if (!sorted_lps.SequenceEqual(s.ladder_profiles))
await _persist.set(NAME_SPACE, DEFAULT_KEY, s = s.with(ladder_profiles: sorted_lps));
}
} catch (Exception ex) {
Log.Persist.warn($"Error loading {typeof(UserSettings)} from namespace '{NAME_SPACE}', will restore factory defaults and continue as usual: {ex}");
await save_default(s = UserSettings.factory_defaults);
}
lock (_default_settings_lock) {
initialized = true;
if (s != null)
_default_settings_subject.OnNext(_default_settings = s);
}
}
}
// indicates whether or not the settings have been loaded from the server (this happens once, on startup - see the constructor for details)
public bool initialized { get; private set; }
internal UserSettings current {
get {
lock (_default_settings_lock)
return _default_settings ?? UserSettings.factory_defaults;
}
}
/// Subscribing via _persist.subscribe may be cleaner in theory, however using a local event allows observers to be notified immediately.
/// Assuming there aren't any rogue agents saving UserSettings by themselves, there should never be any discrepancies.
public IObservable<UserSettings> subscribe_default_settings() => _default_settings_subject.AsObservable();
public IWindowSettingsManager<GridSettings> create_fills_settings_manager(GridSettings instance_settings) =>
_create_settings_manager(
instance_settings,
_fills_migration_rules,
_fills_propi);
public IWindowSettingsManager<GridSettings> create_mview_settings_manager(GridSettings instance_settings) =>
_create_settings_manager(
instance_settings,
_mview_migration_rules,
_mview_propi);
public IWindowSettingsManager<PNLSettings> create_pnl_settings_manager(PNLSettings instance_settings) =>
_create_settings_manager(
instance_settings,
_pnl_migration_rules,
_pnl_propi);
public IWindowSettingsManager<GridSettings> create_synth_settings_manager(GridSettings instance_settings) =>
_create_settings_manager(
instance_settings,
_synth_migration_rules,
_synth_propi);
public IWindowSettingsManager<GridSettings> create_reconcile_report_settings_manager(
GridSettings instance_settings) =>
_create_settings_manager(
instance_settings,
_reconcile_report_migration_rules,
_reconcile_report_propi);
public async Task save_default(UserSettings value) {
// notify observers before persisting so the changes are reflected immediately in the ui
lock (_default_settings_lock) {
_default_settings_subject.OnNext(_default_settings = value);
}
await _persist_async();
}
IWindowSettingsManager<T> _create_settings_manager<T>(T instance_settings, IEnumerable<ISettingsMigrationRule<T>> migration_rules, IImmutableProperty<UserSettings, T> propi) where T : class {
if (instance_settings != null && migration_rules.merge().apply(instance_settings, out var new_settings))
instance_settings = new_settings;
return new WindowSettingsManager<T>(this, instance_settings, propi.get, propi.set);
}
async Task _persist_async() {
try {
await _persist.set(NAME_SPACE, DEFAULT_KEY, _default_settings);
} catch (Exception ex) {
Log.Persist.warn($"Error persisting {typeof(UserSettings)} in namespace '{NAME_SPACE}': {ex}");
}
}
}
}
@@ -1,77 +1,77 @@
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace mbts.ui.shell {
public enum DockState {
FLOATING = 1,
TOP = 2,
BOTTOM = 3,
LEFT = 4,
RIGHT = 5,
}
[ProtoContract]
public class WindowPosition {
[ProtoMember(3)]
public int width;
[ProtoMember(4)]
public int height;
[ProtoMember(5)]
public int left;
[ProtoMember(6)]
public int top;
[ProtoMember(7)]
public bool is_maximized;
[ProtoMember(8)]
public string host_id;
[ProtoMember(9)]
public int tab_index;
[ProtoMember(100), DefaultValue(false)]
public bool horizontal = false;
[ProtoMember(101), DefaultValue(true)]
public bool show_text = true;
[ProtoMember(102), DefaultValue(true)]
public bool always_on_top = true;
//[ProtoMember(103)] //used
[ProtoMember(104)]
public string custom_title;
}
[ProtoContract]
public class WindowState {
[ProtoMember(1)]
public string owner;
[ProtoMember(2)]
public byte[] app_data;
//optional bool is_open = 3 [default = true];
//optional bool is_favorite = 4;
//optional string title = 5;
//optional string id = 6;
// optional bool is_loaded = 7 [default = false];
[ProtoMember(8)]
public WindowPosition position;
[ProtoMember(9)]
public string title; // for debugging
}
[ProtoContract]
public class ModuleState {
[ProtoMember(1)]
public string name;
[ProtoMember(2)]
public byte[] app_data;
}
}
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace mbts.ui.shell {
public enum DockState {
FLOATING = 1,
TOP = 2,
BOTTOM = 3,
LEFT = 4,
RIGHT = 5,
}
[ProtoContract]
public class WindowPosition {
[ProtoMember(3)]
public int width;
[ProtoMember(4)]
public int height;
[ProtoMember(5)]
public int left;
[ProtoMember(6)]
public int top;
[ProtoMember(7)]
public bool is_maximized;
[ProtoMember(8)]
public string host_id;
[ProtoMember(9)]
public int tab_index;
[ProtoMember(100), DefaultValue(false)]
public bool horizontal = false;
[ProtoMember(101), DefaultValue(true)]
public bool show_text = true;
[ProtoMember(102), DefaultValue(true)]
public bool always_on_top = true;
//[ProtoMember(103)] //used
[ProtoMember(104)]
public string custom_title;
}
[ProtoContract]
public class WindowState {
[ProtoMember(1)]
public string owner;
[ProtoMember(2)]
public byte[] app_data;
//optional bool is_open = 3 [default = true];
//optional bool is_favorite = 4;
//optional string title = 5;
//optional string id = 6;
// optional bool is_loaded = 7 [default = false];
[ProtoMember(8)]
public WindowPosition position;
[ProtoMember(9)]
public string title; // for debugging
}
[ProtoContract]
public class ModuleState {
[ProtoMember(1)]
public string name;
[ProtoMember(2)]
public byte[] app_data;
}
}
@@ -0,0 +1,40 @@
#nullable enable
namespace Spark.Model {
using bts.api;
using bts.spark;
using mbts.ui;
using Spark.ViewModel.Commands;
using System;
using System.Windows.Input;
using System.Windows.Media;
class SparkMenuItemToggleModel : SparkCommand, ISelectable {
readonly IToggleCommand _cmd;
public SparkMenuItemToggleModel(
string? title,
ImageSource? icon = null,
bool show_in_toolbar = true,
bool show_in_context_menu = true,
KeyGesture? key_gesture = null,
IToggleCommand? cmd = null)
: base(title, icon, show_in_toolbar, show_in_context_menu, key_gesture) =>
_cmd = cmd ?? new ToggleCommand();
public event Action<bool>? is_selected_changed {
add => _cmd.is_selected_changed += value;
remove => _cmd.is_selected_changed -= value;
}
public bool is_selected {
get => _cmd.is_selected;
set => _cmd.is_selected = value;
}
public override void execute(IBus bus) =>
is_selected = !is_selected;
}
}
@@ -0,0 +1,33 @@
#nullable enable
namespace bts.api.position {
using bts.api.core;
using bts.api.orderman;
using bts.shell.pnl;
using mbts.ui;
using Spark.Trading;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
interface IPositionModel {
// positions
IObservable<TableUpdate<(SecurityImmutable?, PositionUnitImmutable), int>> on_positions { get; }
IObservable<TableUpdate<(SecurityImmutable? sec, RetrievedExchangePositionImmutable exch_pos), AccountSecurityKey>> on_exchange_positions { get; }
IObservable<TableUpdate<ReconcileReportRowData, AccountSecurityKey>> merged_positions { get; }
// pnl
IObservable<TableUpdate<(SecurityImmutable?, PNLUnitImmutable, QuantityConversionData<double>), int>> on_pnl { get; }
IObservable<TableUpdate<PNLRowData, AccountSecurityKey>> security_account_pnl { get; }
IObservable<TableUpdate<(SecurityImmutable?, PositionUnitImmutable), int>> on_security_positions(
uint security_key);
Task<bool> override_cpp_async(IEnumerable<(uint security_key, double cpp)> cpp_overrides);
Task<IReadOnlyList<PositionServiceOpResponseImmutable>> reset_positions(
ResetPositionParametersImmutable new_positions);
}
}
@@ -0,0 +1,72 @@
#nullable enable
namespace Spark.Model.Trading {
using bts;
using bts.api;
using bts.api.core;
using bts.api.orderman;
using bts.api.position;
using bts.shell.pnl;
using bts.spark;
using mbts.spark;
using Spark.Core.Reactive;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
[Export]
class OrderDataSource {
[ImportingConstructor]
public OrderDataSource(
IBus bus,
AdminModel admin_model,
SecurityStore security_store,
OrderService order_service,
ISecurityAuxiliaryDataModel security_auxiliary_model,
ErrorReporter error_reporter
) {
var scheduler = ThreadPoolScheduler.Instance;
var interval = TimeSpan.FromMilliseconds(100);
orders = admin_model
.permission_filter(
order_service.subscribei_orders()
.Naggle(interval, scheduler),
o => o.account_id())
.join(security_store, o => o.security_key())
.Table()
.Cache();
working_orders = orders.Filter(tup => tup.order.is_active()).Cache();
security_orders = orders
.SelectKeyValue(tup => new OrderSecurity(tup), OrderSecurityHelper.key_fn)
.GroupTable(OrderSecurityHelper.key_fn, tup => tup.order.Def.SecurityKey)
.Cache();
account_security_orders = orders.GroupTable(
t => t.order.Key,
t => new AccountSecurityKey(t.order.account_id(), t.order.security_key()))
.Cache();
working_account_security_orders = working_orders
.Filter(o => o.order.is_exchange_order())
.GroupTable(
t => t.order.Key,
t => new AccountSecurityKey(t.order.account_id(), t.order.security_key()))
.Cache();
}
public IObservable<TableUpdate<(SecurityImmutable? sec, OrderRecordImmutable order), uint>> orders { get; }
public IObservable<TableUpdate<(SecurityImmutable? sec, OrderRecordImmutable order), uint>> working_orders { get; }
public IObservable<TableUpdate<TableUpdateGrouping<OrderSecurity, uint, uint>, uint>> security_orders { get; }
public IObservable<TableUpdate<TableUpdateGrouping<(SecurityImmutable? sec, OrderRecordImmutable order), uint, AccountSecurityKey>, AccountSecurityKey>> account_security_orders { get; }
public IObservable<TableUpdate<TableUpdateGrouping<(SecurityImmutable? sec, OrderRecordImmutable order), uint, AccountSecurityKey>, AccountSecurityKey>> working_account_security_orders { get; }
}
}
Loaded 100 of 926 files, more files were not shown because too many files have changed in this diff. Show more