Compare commits

..
901 Commits
Author SHA1 Message Date
johncolvin-og ea4e599ac6 fix build: Fix a few path errors in publish target 2023-05-31 21:59:51 -04:00
Taha fd2ba70031 Culling the logs 2023-05-29 11:35:49 -04:00
Taha ab410c339f Order Tickets from the sheets are defaulted correctly now 2023-05-29 10:32:29 -04:00
John Colvin 9e3f16d8bc fix build: Update externals so prod builds in new docker 2023-04-05 11:45:24 -04:00
John Colvin a3f194d708 build (web): Upgrade web build to net7.0 2023-04-05 11:39:37 -04:00
John Colvin bf87c46fcd fix build: Remove inappropriate ThreadStatic attr
This has likely been incorrect for a while. The problem surfaced after
upgrading to net7.0, as the new framework emits a warning (CA2259) when the
attribute is associated with a non-static field.
2023-03-07 16:30:59 -05:00
John Colvin 222d4b266e build: Disable warning cs8981
This is a new warning, introduced in net7.0, that disallows lowercase
class names. Our spark_crypto.prod branch currently uses protoc v3.19.1,
which is incompatible with this new warning, as it generates
classes with lowercase names. We can re-enable the warning when we
upgrade protoc to 3.21.12 (this has been done in the api server branch).
2023-03-07 16:25:21 -05:00
John Colvin d593eaf058 build: Upgrade TargetFramework to net7.0
We've been using several net7.0 preview features for a while now. Now that a
stable net7.0 release is available, it is time upgrade officially. This also
aids the effort to build csharp on Linux, where these preview features didn't
work out of the box. Lastly, trying to make these preview features work would
be a waste of time, as namespaces/interfaces in the official release have
changed in a way that isn't backwards compatible w/ the preview features.
2023-03-07 16:17:39 -05:00
John Colvin 55d021ccb1 fix build (publish): Copy libspark.dll to publish dir
Bugs (fixed):
  * Spark.exe generated by the installer crashes immediately on launch because
    it cannot find the libspark.dll.

  Cause: Sure enough, libspark.dll isn't in the install folder
  (AppData\Roaming\bts\Spark)

* Build libspark explicitly
* Fix libspark.dll copy src path
2023-02-07 16:41:11 -05:00
John Colvin b02f814c65 fix (ui): Remove context menu items that do nothing
They were accidentally brought over from Edge. Their functionality
hasn't been implemented in Spark.
2023-01-23 01:34:55 -05:00
John Colvin 8c42aa93a2 chore: Remove unused code 2023-01-23 01:34:55 -05:00
John Colvin 357bc5ad44 fix (ui): Format perp futs 'Perp' suffix (not bogus exp) 2023-01-23 01:34:55 -05:00
John Colvin 07fb9e8eb7 ui (pnl): Use 'default_text' foreground in popup titles
Previously, the foreground for some popups was a hardcoded dark gray,
which became hard-to-read following the Dark Theme changes.
2023-01-23 01:34:55 -05:00
John Colvin 9f9fc4c8ab fix (analytics-exps): Wait for sym list before loading selection
Bugs (fixed):
   * The selected symbols aren't restored with the workspace

   Cause: The selected symbols were getting loaded once, in the ctr, before the
   list of symbols had been properly initialized. The view automatically
   deselects items that aren't in the ItemsSource.
2023-01-22 12:23:03 -05:00
John Colvin 2aef052398 ui (pnl): Use gray font color when pnl is zero 2023-01-22 12:23:03 -05:00
John Colvin 1c2027506a refactor: Clean up NullableColor/FontWeightProto 2023-01-22 12:23:03 -05:00
John Colvin c3274b2008 refactor: Rename argb_color -> to_uint
This is a more appropriate name
2023-01-22 00:11:28 -05:00
John Colvin 99aef9e86e refactor: Get rid of redundant prop 'NullableColorProto.argb'
It was a relic of the past. Although different fns are called in the props'
getters ('rgb_color' vs 'argb_color'), both ultimately return the same value.
2023-01-22 00:09:38 -05:00
John Colvin 8e9233022e fix (mini-ob): Return root element in CancelColumn.view_factory
Bugs (fixed):
  * Mini Orderbook crashes immediately when opened

  Cause: The (cell) view_factory fn wasn't returning the cell's root
  element, and was instead returning the root's child element.
  As a result, when the row attempted to add this element to its visual
  tree, the following exception was thrown:

    System.ArgumentException: Specified Visual is already a child of
    another Visual or the root of a CompositionTarget.
2023-01-21 13:41:04 -05:00
arhamGIT 4c91538f22 base websockets working 2023-01-04 04:34:44 -05:00
Taha Afzal 320427c9c5 Merge branch 'spark_crypto.dev' of bitbucket.org:bluetradesys/spark into spark_crypto.dev 2022-12-25 16:17:12 -05:00
Taha Afzal 5e8543902e Sheet theos change colors for contracts that are in a task 2022-12-25 16:17:01 -05:00
John Colvin edae3c9ab7 build (refactor): Remove 'zip' opt from publish_spark
The slight convenience afforded by this opt doesn't seem worth the
additional complexity. This script produces a self-contained application
folder. Decisions on what to do with that folder (whether or not to zip
it, etc.) are best left upstream.
2022-12-23 11:40:35 -05:00
John Colvin fd9892c6b6 fix: Prevent raw_pb_callback premature garbage collection
Bugs (fixed):
   * Startup crash w/ error message: "A callback was made on a garbage
     collected delegate of type ApiNativeMethods.raw_pb_callback"

   Cause: The callback is only referenced in unmanaged c++. Without references
   in managed code, the Garbage Collector deems the delegate eligible for
   collection before the callback has finished execution.

   Note: The original solution forced a reference in managed code by storing it
   in a class-member 'keepalive' dictionary, whose life isn't bound to the
   [synchronous] scope of the 'send' method. The callback would then remove
   itself from the dictionary in its last line of code. While this reduced the
   chance of such an error occurring, occassional crashes persisted
   (particularly in low-bandwidth environments). I suspect the frequency at
   which garbage-collector threads run is inversely related to the frequency
   at which data arrives from the server, as the latter triggers execution of
   higher-priority threads.

   Steps to repro:
      1. Insert a Thread.Sleep statement (1000 ms should be sufficient) after
         the call that removes the last reference to the delegate (i.e., make
         the thread sleep for a significant amount of time in the callback
         AFTER it becomes eligible for garbage collection).

      2. Build, run, and observe crash on startup.

   Solution: Wrap the callback in another class, and store the wrapper
   in the dictionary rather than the callback itself. The reason why this
   works isn't totally clear, however its effectiveness has been verified
   with the repro (described above).
2022-12-23 11:25:07 -05:00
Taha Afzal 45668baaf8 Adding code to Main 2022-12-20 12:17:51 -05:00
Taha Afzal 305cc0e01c Adding simple concrete classes 2022-12-20 12:00:46 -05:00
Taha Afzal f0f365538b Initial check in for Websocker skeleton 2022-12-19 23:45:52 -05:00
Taha Afzal f9bba0baed Merge branch 'spark_crypto.dev' of bitbucket.org:bluetradesys/spark into spark_crypto.dev 2022-12-19 17:41:38 -05:00
John Colvin 306c18065a chore: Add csproj bones for websocket api 2022-12-19 14:25:37 -05:00
John Colvin c64c71c98c fix build (sparkd install): Copy plugins to install dir 2022-12-15 12:47:35 -05:00
John Colvin 7de87c1c25 ui (refactor): Consolidate (Repeat)Button colors to one class
The only difference between a RepeatButton and a regular Button is in
the click-behavior (they should look identical).
2022-12-15 12:47:35 -05:00
John Colvin 12716bb6e1 fix: Add a couple null checks 2022-12-15 12:47:35 -05:00
John Colvin 8e68d573ff ui (volsurface): Update oxyplot to get rid of 'dummy' win 2022-12-15 12:47:35 -05:00
Taha Afzal dd66e94bfd Merge branch 'spark_crypto.prod' of bitbucket.org:bluetradesys/spark into spark_crypto.prod 2022-12-09 16:59:50 -05:00
Taha Afzal d399f75648 Decreasing the log rate on the server 2022-12-09 16:59:08 -05:00
John Colvin 937173dd2f ui (volsurface): Update oxyplot to get rid of 'dummy' win 2022-12-09 13:23:44 -05:00
Taha Afzal f1f7a40fba Changing some Sheet UI Defaults 2022-12-09 01:53:08 -05:00
Taha Afzal 5522d364d4 Fixing Sheets and SpreadBox colors 2022-12-09 00:47:47 -05:00
John Colvin 3a218d246e ui: Style ListBoxEx w/ dark theme colors
This control used in grid filters (multi-select)
2022-12-08 13:52:14 -05:00
John Colvin bafc28e3bc ui: Touch up orderbook panel (dark theme) 2022-12-08 13:52:14 -05:00
John Colvin 6d1eb474c4 ui (grid settings): Align column-list cell params
The [vertical] alignment issue was only noticeable in the pnl settings dialog
(its cell params section is taller than those in other settings dialogs), where
the shorter columns list was center aligned with the taller cell params.
2022-12-08 13:52:14 -05:00
John Colvin d172f4ffab ui: Touch up grid settings dialogs (dark theme) 2022-12-08 13:52:13 -05:00
John Colvin c527b6e84f ui: Touch up AlgoStudio (dark theme) 2022-12-08 13:51:55 -05:00
John Colvin b8c7abd6b3 ui: Style TickUpDown ctrls w/ dark theme colors 2022-12-08 13:30:55 -05:00
John Colvin fea8e184c1 style: Sort tag attributes in xaml
* Put attached props before regular (i.e., not attached) props
* Sort alphabetically, with exceptions for props that are logically
  grouped together. For example Width/MinWidth/MaxWidth may be
  adjacent, as they are all 'width' props.
2022-12-08 13:30:55 -05:00
John Colvin 44a7bc0de9 style: Format large xaml files
* Improves readability
* Adds new lines to make navigating through the tags easier
* Mostly just white space changes

fix add empty lines

fix empty lines (reword commit to 'white space changes')

fix white space
2022-12-08 13:30:55 -05:00
arhamGIT 4bad9ef183 ladder lines 2022-12-08 13:30:55 -05:00
arhamGIT 590835c627 ladder changed 2022-12-08 13:30:54 -05:00
arhamGIT 997766df92 partial PNL header fix 2022-12-08 13:30:54 -05:00
arhamGIT cdbf66cd6c grid fixed with new row colors 2022-12-08 13:30:54 -05:00
arhamGIT 4c90eed59e bunch of changes for dark theme 2022-12-08 13:30:54 -05:00
John Colvin d260f8ce2c ui: Hardcode dark theme 2022-12-08 13:30:54 -05:00
Taha Afzal 12d0afb215 Merge branch 'spark_crypto.tasking_eye' of bitbucket.org:bluetradesys/spark into spark_crypto.tasking_eye 2022-12-06 15:21:46 -05:00
Taha Afzal a9040f5f8f For TaskingEye, side is not a part of the algo any more. Therefore selecting the bids and starting an eye, makes it go shoot at the bid, and vice verca for the asks 2022-12-06 15:21:37 -05:00
Taha Afzal 6e6acb5a71 Fix for TaskingEyeAlgo with empty security lists (ie when algo is launched from the ladder) 2022-12-06 15:17:54 -05:00
Taha Afzal 256697d5b0 Side is a parameter of TaskingEyeAlgo, it is inferred from the OrderDefinition (like other algos) 2022-12-06 11:06:44 -05:00
Taha Afzal be9067b22e AlgoWrapper was not publishing the filled fractional qtys, fixed now 2022-12-05 22:59:59 -05:00
Taha Afzal a5874a59f0 AlgoWrapper was not reporting fractional qty fills, this fixes it now via using the get_quantity function in orderman_common.h 2022-12-05 21:56:50 -05:00
Taha Afzal e8405e5638 OrderServiceServer starts calling ServiceBridge's do_work only once it gets the ready signal from ServiceBridge 2022-12-05 14:33:04 -05:00
Taha Afzal ab70c9dfb1 Fixing problem with TaskingEye for fractional shot qtys 2022-12-04 23:21:23 -05:00
Taha Afzal 1e4d8584c7 Merge branch 'spark_crypto.tasking_eye' of bitbucket.org:bluetradesys/spark into spark_crypto.tasking_eye 2022-12-04 20:36:25 -05:00
Taha Afzal 29eef77099 ServiceBridge now periodically publishes the TheoEvent (with a flag indicating such). This helps the algos get the theos without waiting for the next update 2022-12-04 20:36:10 -05:00
Taha Afzal c50e89ae78 Merge branch 'spark_crypto.tasking_eye' of bitbucket.org:bluetradesys/spark into spark_crypto.tasking_eye 2022-12-03 00:28:12 -05:00
Taha Afzal 89917713d6 Tasking eye UI work in the sheets 2022-12-03 00:28:00 -05:00
Taha Afzal 1e0ac46e07 Account name is part of the Tasking Eye Algo now 2022-12-02 23:18:06 -05:00
Taha Afzal 6279b8f5f5 Securities (string of sec_ids unfortunately) is a parameter in Tasking Eye Algo now 2022-12-02 15:44:25 -05:00
Taha Afzal 4007c87e20 Merge branch 'spark_crypto.tasking_eye' of bitbucket.org:bluetradesys/spark into spark_crypto.tasking_eye 2022-12-01 09:50:47 -05:00
Taha Afzal ec0f42e76c Adding timer for the theo publishing time 2022-12-01 09:50:37 -05:00
Taha Afzal 99f63c2a6f Fixed a big with the shot throttle 2022-11-30 21:42:54 -05:00
Taha Afzal 12ac20f756 TaskingEyeAlgo code complete, it is firing orders and correctly (needs more testing and ui integration) 2022-11-30 15:39:00 -05:00
Taha Afzal 9d36d74005 TaskingEyeAlgo correctly subscribes and receives driver books 2022-11-29 13:42:15 -05:00
Taha Afzal da2cc977a0 TaskingEyeAlgo hooked up to theos 2022-11-29 00:11:04 -05:00
Taha Afzal 84e7bdb586 Adding TaskingEyeAlgo 2022-11-28 16:57:12 -05:00
Taha Afzal b062a229c8 Added on_theos to IAlgoOrder, and hooked up the plumbing 2022-11-28 10:54:38 -05:00
Taha Afzal 8680b3d815 Publishing the interp theos to the server is almost done 2022-11-25 22:20:08 -05:00
Taha Afzal 6ab0e4c5a7 Merge branch 'spark_crypto.tasking_eye' of bitbucket.org:bluetradesys/spark into spark_crypto.tasking_eye 2022-11-25 16:36:34 -05:00
Taha Afzal 867bcf97d0 Added InterpTheosServerPublisher, which allows to publish precomputed theos to the server 2022-11-25 16:36:26 -05:00
Taha Afzal 360bf9b37e Added get_driver_sec to ITheoCalculator 2022-11-25 16:22:10 -05:00
Taha Afzal 4d85106fbf Added server method to publish precomputed theos, feed it into a calculator, and publish the calculator as an event 2022-11-23 12:52:01 -05:00
Taha Afzal 64a253b581 Fixed the vol change in day bug (difference of uint64s was being assigned to an int32) 2022-10-26 09:37:25 -04:00
Taha Afzal 5f379c1356 SpreadBox minor button display fixes 2022-10-13 07:32:03 -04:00
Taha Afzal 76c80383ce Merge branch 'spark_crypto.dev' into spark_crypto.prod 2022-10-13 00:55:11 -04:00
Taha Afzal e5a6ea80f0 Making the SpreadBox button click more obvious (ToolStripButtons do not have the button like feel of a click) 2022-10-13 00:54:13 -04:00
Taha Afzal b921e644df Merge branch 'spark_crypto.dev' into spark_crypto.prod 2022-10-13 00:13:42 -04:00
Taha Afzal 1c3fb8c192 Merge branch 'spark_crypto.dev' of bitbucket.org:bluetradesys/spark into spark_crypto.dev 2022-10-13 00:00:40 -04:00
Taha Afzal d530d86a30 Merge branch 'spark_crypto.prod' of bitbucket.org:bluetradesys/spark into spark_crypto.prod 2022-10-12 23:57:08 -04:00
Taha Afzal 9d9229ef56 Merge branch 'spark_crypto.spread_creation' into spark_crypto.dev 2022-10-12 23:43:11 -04:00
Taha Afzal 6f6f3c0800 RFQ qty and sides, sent from the client, are now sent over to Deribit 2022-10-12 23:39:44 -04:00
Taha Afzal 7b234044f6 Added controls in the spreadbox that allow for specifying qty and side for an RFQ 2022-10-12 20:08:24 -04:00
John Colvin d46c82f34c feat (ladder): Add side/qty inputs for rfqs 2022-10-12 15:41:57 -04:00
Taha Afzal 4d5af610f0 Added an 'RFQDialog' tag to SparkTags, that launches athe RFQDialog window 2022-10-12 11:55:19 -04:00
Taha Afzal 1e94466f24 RFQ for new spreads are now routed to emumba's create_combo method 2022-10-11 15:55:55 -04:00
Taha Afzal 3210c0bce4 Combo creation at Deribit is turned on from the UI now (it was disabled with a boolean switch prior to this commit) 2022-10-11 10:53:09 -04:00
Taha Afzal 849f4ac579 Merge branch 'spark_crypto.prod' of bitbucket.org:bluetradesys/spark into spark_crypto.prod 2022-10-10 15:14:40 -04:00
John Colvin 6d56f67697 feat: Add volsurface graph settings dialog
A lot of the vm code was already there, but I cleaned it up a bit. The view was
ported over from edge and also cleaned up/tweaked a bit.
2022-10-10 14:46:34 -04:00
John Colvin c0289719e7 fix (pre-emptive): Add null check in 'DisposeAll' fn
Bugs (fixed):
  * The volsurface graph settings dialog crashes when you click OK/Apply

    Note: This fix is 'pre-emptive' because I saw the bug while working on the
    vs graph settings dialog. That feat will be added shortly in a subsequent
    commit (I wanted to commit the fix first so the bug wouldn't be in the
    official 'feat' revision/commit).

    Cause: A null ref ex is thrown in DisposeAll, because the List of IDisposables
    to dispose contains null items.

    Another way to fix the bug would have been to make sure null items aren't
    added to these Lists in the first place. However, that places the burden (to
    check for null) on the callers' shoulders, and leaves open the potential for
    this bug in every place where 'DisposeAll' is called.
2022-10-10 14:35:29 -04:00
John Colvin a32e969b39 fix (ui): Fix ColorPickerControl/Popup SelectedColor binding
There were a few issues here:
  * The ColorPickerPopup was binding it's own SelectedColor prop to the internal
    ColorPickerControl's SelectedColor prop. The SelectedColor prop is typically also
    bound to some (external) viewmodel's 'color' prop. This is problematic as
    Dependency Properties can only be associated with one 'Write' binding.

  * The code designed to keep various sub-color properties in sync with the
    result color was confusing, and didn't seem to work. For example, the ARGB
    sliders' values didn't match those of the 'result' color.
2022-10-10 14:22:34 -04:00
John Colvin f5899e7781 fix (vs graph): Bind series vm color to correct OxyPlot prop
Bugs (fixed):
  * The VolSurface graph colors don't reflect the settings. They appear to be
    randomly generated.

   Cause: The series vm's color prop was bound to 'TextColor' in the model; it
   should have been bound to 'Color'
2022-10-10 11:17:17 -04:00
John Colvin ed07c956a7 ui: Remove quotes around 'Enter' in col filter prompt
Looks cleaner this way, and isn't clipped given the current width
2022-10-10 11:15:14 -04:00
Taha Afzal 2022ee5a07 Completing Deribit execution test 2022-10-10 11:01:59 -04:00
Taha Afzal a0bc1e8691 Spreader can handle options now 2022-10-09 23:56:38 -04:00
Taha Afzal c1951ac49a Added ability to view md/theo in USD, in the sheets 2022-10-08 21:45:57 -04:00
John Colvin e159e0e77b ui (man fills): Add 'Time Entered' column 2022-10-07 15:04:36 -04:00
John Colvin 6bbd4134ec ui (man fills): Use foreground to indicate buy/sell 2022-10-07 15:04:35 -04:00
John Colvin 8a72b2150a ui (rec rep): Use font weight to indicate price/qty discreps 2022-10-07 15:04:35 -04:00
John Colvin e4d5d1eeb2 ui (rec rep): Use foreground to indicate long/short pos 2022-10-07 15:04:35 -04:00
John Colvin 6bf2726b63 ui (rec rep): Filter out system spread positions
The exchange splits spread positions into the individual legs
2022-10-07 14:50:10 -04:00
Taha Afzal a63af0cb46 Manual tests for Deribit order execution 2022-10-06 22:37:39 -04:00
John Colvin b2a7e1d2ed feat: Add 'Send RFQ' button to ladder 2022-10-05 13:35:00 -04:00
John Colvin 32a38b3b5a refactor: Remove unused code 2022-10-05 13:35:00 -04:00
John Colvin 8533bcf0a7 style: Format LadderView.xaml
It's a big file. Irregular formatting/spacing makes it difficult to navigate.

* Use max line width of 100
* Add empty line after multiline tags
* Trim trailing white space
* Rename terse xml namespaces:
   - 'converters' -> 'cv'
   - 'spark' -> 'sp'
   - 'mbts' -> 'u'

fix fmt ladder
2022-10-05 13:34:39 -04:00
John Colvin e00eae1129 refactor (ui): Enable auto-refresh in column-text filters
feat (mview): Enable auto-refresh in security filter

This behavior is (more) consistent with other modern search uis
2022-10-05 01:05:24 -04:00
John Colvin 95595c4cbf fix: Arrange Adorner by target's RenderSize (not Desired)
Bugs (fixed):
  * The Adorner that is used to render a text prompt on top of text boxes appears
  clipped; it doesn't span the width of the TextBox.
2022-10-05 01:05:24 -04:00
John Colvin aad36a4972 fix (mview): Prevent icon flicker when selection changes
Observe changes to MarketViewVM.current_row' rather than
'MarketViewVM.selected_rows'. The latter (collection) is momentarily empty when
the selection switches from one row to another, during which time the buttons
are disabled, hence the flicker.
2022-10-05 01:05:24 -04:00
Taha Afzal cc03f47d70 SpreadBoxes can be brought up from MV 2022-10-04 22:17:46 -04:00
Taha Afzal 5c5e5c23ef SpreadDisplayForm's start location is not tied to the launching window now 2022-10-04 21:31:30 -04:00
John Colvin 4b531a2a1a feat: Add 'Send RFQ' button to mview 2022-10-04 18:07:30 -04:00
John Colvin 35530bec0b refactor: Remove unused variable 2022-10-04 16:42:50 -04:00
John Colvin 5853bb2436 refactor: Make RFQSend tag data immutable
It's safer this way. The data doesn't need to be mutated.
2022-10-04 16:39:01 -04:00
John Colvin bfdf45d30d fix (ui): Fix typo so spreads' qty metadata comes from 1st leg 2022-10-04 15:33:11 -04:00
Taha Afzal a330bc5020 MV and Ladder use GreekTuple.normalized_theo now 2022-10-03 23:20:48 -04:00
Taha Afzal 66f68ef3ec Fixing the spread filled price (EMNativeOrder needed to ignore spread_leg like the GLBX and ICENativeOrders 2022-10-03 23:19:10 -04:00
Taha Afzal d6e651129b RFQs are fully hooked up 2022-10-03 14:54:09 -04:00
Taha Afzal d4a59b8253 UI sends RFQ requests (and almost combo creations) 2022-10-03 00:04:55 -04:00
Taha Afzal 569f1460a4 Wiring up RFQ sending 2022-10-03 00:04:55 -04:00
Taha Afzal 2f369dbd57 RFQ wiring complete 2022-10-02 22:20:44 -04:00
Taha Afzal 444e486862 Changing RFQ Proto 2022-10-01 22:15:05 -04:00
Taha Afzal b42504d827 RFQ work to identify the spreads 2022-09-30 15:26:22 -05:00
Taha Afzal 18ac85a454 SpreadBox can identify listed spreads, shows the market data as well as allows orders (through ladder) and RFQs 2022-09-30 15:26:22 -05:00
Taha Afzal 788a1a06c5 Greeks for Spreads and Futures are added to bus's Greeks 2022-09-30 15:26:22 -05:00
John Colvin 787b485bce fix (ladder): Init qty input to null (not nan)
Bugs (fixed):
  * The ladder qty box defaults to 'NaN' when opened
  * Cannot change qty input via keyboard until 'NaN' is cleared
2022-09-28 22:57:36 -05:00
John Colvin 788df0e888 fix build (gcc-11): Include optional 2022-09-28 21:22:47 -05:00
Taha Afzal 916532f7c5 Fixing formatting of Deribit spreads 2022-09-28 21:22:47 -05:00
Taha Afzal 3c511bb177 RFQ hooked up on the server side 2022-09-28 21:22:47 -05:00
Taha Afzal 49f13755c6 Adding RFQ to OrderService interface 2022-09-28 21:22:47 -05:00
Taha Afzal dcb4b1ae7e Spread leg fills at Deribit now have the correct prices 2022-09-28 21:22:47 -05:00
Taha Afzal 2152b48fe2 Spread execution is almost done, leg prices are not correct 2022-09-28 21:22:47 -05:00
John Colvin b6f2f99f21 improve: Get spread qty metadata from first leg 2022-09-28 21:22:47 -05:00
John Colvin c44df8ec06 style: Add documentation to ContractLegEnumerable 2022-09-27 17:03:58 -05:00
John Colvin 493f082d6d fix (mview): Apply sec price format to theo & driver 2022-09-27 16:01:49 -05:00
John Colvin bbe76b2709 feat (ladder): Show theo, delta, vega in left panel 2022-09-27 15:53:22 -05:00
John Colvin ce8eda24fc refactor: Make vm prop changed subs more performant 2022-09-27 10:53:39 -05:00
John Colvin 9f9113bf9a refactor: Clean up LadderSettingsVM a bit
* Add readonly modifiers
* Declare 1 member per statement (don't separate members of same type by commas)
2022-09-26 13:34:50 -04:00
John Colvin a199595938 feat (part): Add 'Spread Box' menu item in mview
It posts the selected securities to the 'SpreadBox.ShowSecurities' tag.

TODO: Hook up handler to launch spread boxes in response to the
'SpreadBox.ShowSecurities' tag
2022-09-22 23:51:51 -04:00
Taha Afzal 83de5fac75 Deribit spread market data is now written to shared memory 2022-09-22 23:51:48 -04:00
Taha Afzal c688657d53 Vol surfaces are curtailed to the newest 500 at server startup 2022-09-22 23:51:41 -04:00
John Colvin a5c62c66b1 refactor (ladder): Get theos from Greeks tag
The old tag, KeyedTheos, is redundant and will be removed soon
2022-09-22 22:04:44 -04:00
John Colvin 6d595d18ee fix: Fix typo in requirements.txt ('=' -> '==') 2022-09-21 01:55:28 -04:00
John Colvin 946e8f1c47 Update externals
* Removes no-longer necessary node_modules dir
2022-09-21 00:17:31 -05:00
John Colvin b765c3756d chore: Remove arbitrary [vscode] 'tasks.json'
Vscode json files (settings, tasks, launch, etc.) should be tracked in the
dev/<name> dirs
2022-09-21 00:17:31 -05:00
John Colvin 54dc7bf6c3 fix (webapp): Add method without 'set_' prefix in generated js
We already do this for 'get_' prefixes
2022-09-21 00:17:31 -05:00
John Colvin 6142a08db6 build (client): Copy libspark.dll to 'publish' dir
This dll isn't automatically copied when 'dotnet publish' is executed, because
dotnet core isn't really integrated with cpp
2022-09-21 00:17:31 -05:00
John Colvin ca59976e00 fix build (cpp win): Use explicit void template arg in memcpy 2022-09-21 00:17:31 -05:00
John Colvin 7f7a160916 fix build (cpp win): Disable ccapi code in windows 2022-09-21 00:17:31 -05:00
John Colvin c8eb51c303 build (refactor): Move web build scripts to tools/py
Even though they're specific to the web CMakeLists proj, it's good to have all
build scripts in one place
2022-09-21 00:17:31 -05:00
John Colvin 4160233a58 build: Get rid of redundant setup_builds.sh
The new build_sparkd.py script handles both configuration and actual build
2022-09-21 00:17:31 -05:00
John Colvin c5f79f754b build: Compile sparkd w/ newer gcc v11 2022-09-21 00:17:31 -05:00
John Colvin 5f568d681a Update docker/linux to get gcc v11 2022-09-21 00:17:28 -05:00
John Colvin 83a2147428 build (sparkd): Enable Binance for ccapi 2022-09-21 00:14:38 -05:00
John Colvin 9dd2cee6d9 refactor: Repurpose ccapi ftx-impl for general use 2022-09-21 00:14:38 -05:00
Taha Afzal 57365013bd CCMarketDataListener is mostly complete, error handling and RFQs/state remains 2022-09-21 00:14:38 -05:00
Taha Afzal 3d55ef075b CCMarketDataListener writes its security to shared memory now 2022-09-21 00:14:38 -05:00
Taha Afzal 14da6461b1 Constructor added to CCMarketDataListener 2022-09-21 00:14:38 -05:00
Taha Afzal e84d3df024 Adding skeleton 2022-09-21 00:14:38 -05:00
John Colvin ed38fe0ce9 fix build (web): Install webpack-cli 2022-09-21 00:14:38 -05:00
John Colvin b5daee3bcf build (web): Replace deprecated fn copy_tree w/ copytree 2022-09-21 00:14:38 -05:00
John Colvin f5c8c29f5a build: Migrate web build to net6.0
Clean up the web build process a bit while we're at it
* Add 'custom_commands' to run npm install in CMakeLists
* Generate tsconfig files for CMake preset configurations
* Rename local variables to _snake_case in CMakeLists
2022-09-21 00:14:38 -05:00
John Colvin 89fa2eae50 build: Enable web build in wsl
Not sure why this was disabled in the first place
2022-09-21 00:14:38 -05:00
John Colvin 41b8c9238c build: Remove server/sparkd from libspark include path 2022-09-21 00:14:38 -05:00
John Colvin 28b66306da chore (linux build): Add benign changes to satisfy gcc11 2022-09-21 00:14:38 -05:00
John Colvin 0bdbc1897a chore (linux build): Add benign changes to satisfy clang13 2022-09-21 00:14:38 -05:00
John Colvin c3d9443a89 build: Automate venv activation in server build 2022-09-21 00:14:38 -05:00
John Colvin 400db13a78 build: Update cmake-min-version to 3.12
Several 'add_compile_definitions' calls were added to the root
CMakeLists.txt as part of the ccapi_cpp lib integration (3.12 is the
version in which that call was introduced)
2022-09-21 00:14:38 -05:00
John Colvin 1d7d5858d5 build: Add script to build sparkd (server)
Similar to the py script used to build spark (client), 'build_spark.py'.
2022-09-21 00:14:38 -05:00
John Colvin 8792f24c5d refactor (build): Move '_exit' to common module logging
Also rename 'exit_msg' since 'exit' is already a builtin fn
2022-09-21 00:14:38 -05:00
John Colvin 76d35b16eb refactor (build): Change SparkPaths to return Path objs 2022-09-21 00:14:38 -05:00
John Colvin 81f7fe72ab refactor (build): Move CWD & SparkPaths to common module file_utils 2022-09-21 00:14:38 -05:00
John Colvin 649ba11edb Update docker/linux 2022-09-21 00:14:32 -05:00
John Colvin 2fc6d7c262 Update externals
* Upgrade ccapi to v5.31.2
* Upgrade emumba to v3.0.6
* Update emumba license (good til 2023-08-01)
2022-09-19 17:50:40 -05:00
John Colvin 45421eedce chore: Move 'CME' specific script to 'cme' dir 2022-09-19 17:50:40 -05:00
John Colvin 8ecb3118e4 refactor (script): Use Path type rather than str 2022-09-19 17:50:40 -05:00
John Colvin 3fdb10890d chore: Rename scripts w/ consistent grammar 2022-09-19 17:50:40 -05:00
John Colvin 2a6224c88d chore: Move py scripts/utils into 'py' dir 2022-09-19 17:50:40 -05:00
John Colvin 8d6ddc8250 chore: Remove unused legacy scripts 2022-09-19 17:50:40 -05:00
John Colvin 6cc8590a1c build: Use venv python to execute buildspark.py
Previously, the virtual environment was activated in the Proto3 build target.
Since the proto3 build target is executed once per proto file, and 91 proto
files are processed during the client cs build, this added significant time to
the build. For example, on [John's]my laptop, activating the venv takes ~0.15s,
which amounts to ~9.55 secs per build.
2022-09-19 17:50:40 -05:00
John Colvin 063d908775 build: Remove unused legacy build script 2022-09-19 17:50:40 -05:00
John Colvin 93565f0ebf fix (jenkins): Update jenkins build procedures for spark-crypto 2022-09-19 17:50:40 -05:00
John Colvin 1d7fcf5d18 build: Move ':create_venv' fn to its own cmd script
So jenkins scripts can reference it as well as buildspark.cmd
2022-09-19 17:50:40 -05:00
John Colvin 897d20f12f build: Refactor buildspark.py so 'build' fn can be imported
This way, jenkins build/deploy py scripts can import 'buildspark.build', and thus
don't have to than re-invent the 'build' wheel
2022-09-19 17:50:40 -05:00
John Colvin a928925252 build: Add 'publish' target to build script for jenkins 2022-09-19 17:50:39 -05:00
John Colvin 4088affa15 fix (sparkd clang): Use 'clang' c compiler w/ 'clang++'
Otherwise cmake picks 'cc' by default

Bugs (fixed):
  * Sparkd crashes due to strange runtime error related to multithreaded access
    of std::promise in clang builds
2022-09-19 17:50:39 -05:00
Taha Afzal 7def6aacd2 MergedMDDaemon has a timer that can periodically remove expired contracts (not enabled right now) 2022-09-16 09:51:27 -04:00
Taha Afzal 94ae1780cd Expired contracts are filtered out from the risk report 2022-09-16 09:51:27 -04:00
John Colvin 2c65c4376b fix (orderbook): Invalid row view when qty display changes
Bugs (fixed):
  * Orderbook qty formatting is inconsistent across Orderbook instances. Within
    one Orderbook, the formatting does seem to be consistent.
2022-09-15 16:02:34 -04:00
John Colvin 68bb3dbfa1 refactor: Remove redundant member 'filled_quantity_text'
It is redundant since another prop, 'display_filled_quantity_text', returns the
exact same value. Eventually we should bring this prop back and replace the
'display_' one. The latter is a legacy prop, from the time before we had proper
Security metadata config. Removing the former for now because having both of
them causes needless confusion.
2022-09-15 15:58:23 -04:00
John Colvin 82a73693a6 fix: Post keyed theos to bus
They were already being created, just not published (perhaps due to a bad merge)
2022-09-15 15:39:38 -04:00
John Colvin 612cd4a4c8 fix: Remove refs to invalid 'default' SecurityImmutable
It's most (probably all) cases where a static 'default' SecurityImmutable is
used, a Nullable<SecurityImmutable> would more accurately represent the state,
which could likely (probably always) be described as "waiting for my real
security from an asynchronous source."

Bugs (fixed):
  * [Race] When Fills window opens, an exception is thrown if the sec-filter's
    items are sorted with a 'default' SecurityImmutable.

    Cause: The static default SecurityImmutable doesn't have an underlying sec
    type (i.e., ContractOneofCase == None). The compare fn doesn't support
    this.

    TODO (maybe): It might be a good idea to 'fix' the compare fn as well
    (i.e., make it support 'None' sec types)

TODO (probably): Remove remaining references to the static default
SecurityImmutable
2022-09-15 15:39:38 -04:00
John Colvin b3828dfc53 refactor: Add lazy param factory logic to SparkCommand
Some SparkCommands convert their parameter to another object that is posted to
the bus when the command is executed. The lazy param factory logic allows those
SparkCommands to hold off on converting the parameter until just before execution.
Thus, these SparkCommands naturally avoid passing invalid parameters to the
delegate (assuming the 'can_execute' evaluates to false for invalid parameters).
2022-09-15 15:39:38 -04:00
John Colvin 01f26567ed refactor: Get rid of SecurityGrid base class
It was pretty old code, and needed to be removed due to its dependence on
non-null SecurityImmutables. The 'default' SecurityImmutable object is invalid,
and throws in its property accessors since the underlying Security object is null.
2022-09-15 15:27:35 -04:00
John Colvin 90d21c9c15 refactor (synth man): No need to support vm reassignment
This was over-engineering..it made things complicated for zero benefit
2022-09-15 15:27:35 -04:00
John Colvin 6351c1340e refactor: Rename SelectManyInSeries -> SelectSeries
Shorter is better in this case
2022-09-15 15:27:35 -04:00
John Colvin 18cdddf76d git: Remove phantom submodule
Can't recall why 'deribit-crypto-connector-demo-application' was added as a
submodule in the first place. It has no actual corresponding files in the main
repository, just an entry in the '.gitmodules' file. Removing it now because
it's causing jenkins builds to fail (jenkins attempts to clone all submodules
in the .gitmodules file, and it doesn't have access permission on this one).
2022-09-08 22:07:05 -04:00
John Colvin b14c8bb1ac Update docker/linux
* Get ccapi deps again (after rebasing the 'ccapi deps' commit in
  docker/linux)
* Upgrade dotnet from a mixture of v2 & 3 to v6.0
2022-09-04 14:37:59 -04:00
John Colvin ceff286120 fix build (server w/ ccapi-disbaled): Add ifdef SPARK_ENABLE_CCAPI ppds 2022-09-02 11:48:12 -04:00
John Colvin 59aa4677e8 Update docker/linux
To get rapidjson-dev (ccapi dep)
2022-09-02 11:31:58 -04:00
John Colvin 996cd4c856 fix (ladder settings ui): Init 'use_self_security' properly
When loading settings obj
2022-09-02 10:30:08 -05:00
John Colvin 9287149c26 refactor: Clean up 'bts.api.core.Result<T>'
Impl ToString while we're at it
2022-09-02 10:14:02 -05:00
John Colvin 306b56a999 fix (hopeful): Make sure callback disposed after subscription
Hopefully this fixes the 'Garbage Collected callback' crash on login
2022-09-02 09:45:02 -05:00
John Colvin 812cf0a43f fix (man fills ui): Remove erroneous extra ladder button 2022-09-02 09:42:25 -05:00
John Colvin 2c539fd833 ui (ladder settings): Select self in sec-picker by default
For pre-existing fair value lines (this behavior's already implemented for new
fair value lines)
2022-09-01 11:07:51 -04:00
John Colvin 334295ed67 fix (ladder settings ui): Fix typo in binding
Resolve discrepancy between between xaml/cs

Bugs (fixed):
  * Color palette section is empty in Fair Value Line color picker
2022-09-01 01:25:58 -04:00
John Colvin c157b9cdfd ui (ladder): Add 'Use Self Security' checkbox to settings ui
Incorporate it into the settings protobuf by making the security_key field
nullable and allowing 'null' to mean 'Use Self Security'
2022-09-01 01:21:09 -04:00
Taha Afzal 8280b7a815 Fixing Deribit order minor issues that were causing the spreader to cancel its child orders 2022-08-31 15:17:35 -04:00
Taha Afzal fb7f982c65 Improving the logs 2022-08-31 15:17:35 -04:00
John Colvin 75b50d93e8 feat (orderbook): Add button to launch Ladder 2022-08-31 01:13:42 -04:00
John Colvin 865bdac9df refactor: Enable nullable in LadderWindow.cs 2022-08-31 01:13:42 -04:00
John Colvin ebe5f468d7 feat (open orders): Add button to launch Ladder 2022-08-29 22:54:48 -04:00
John Colvin 1bc8d886f4 fix: Don't reopen window on synchronous shutdown
Even if 'e.Cancel' is true, as the initial 'Closing' event is always canceled
to allow for asynchronous teardown
2022-08-29 22:54:48 -04:00
John Colvin 38e352e0d3 feat (man fills): Add button to launch Ladder 2022-08-29 22:54:48 -04:00
John Colvin f6079e7031 refactor: Clean up ManualFillsWindowFactory
After refactoring the shell window logic into new 'ManualFillsWindow' class
2022-08-29 22:54:48 -04:00
John Colvin 8c51488190 refactor: Make proper ManualFillsWindow class
Instances of this class are generated instead of 'anonymous' shell windows.
This makes for cleaner code, better stack traces, etc.
2022-08-29 22:54:48 -04:00
John Colvin 9aad08ada6 feat (day fills): Add button to launch Ladder 2022-08-29 22:54:48 -04:00
John Colvin 2d3d11ba59 fix (ui): Set disabled animation KeyTime to 0
Bugs (fixed):
  * The disabled button animation in SparkMenu (toolbar) is laggy
2022-08-29 22:54:47 -04:00
John Colvin 6087953185 feat (fills): Add button to launch Ladder 2022-08-29 22:54:47 -04:00
John Colvin 851654c8a5 feat (rec rep): Add button to launch Ladder 2022-08-29 22:54:47 -04:00
John Colvin 57a4745e29 feat (ladder): Add 'Theo' fair value line 2022-08-28 14:13:10 -05:00
John Colvin 32cd00895e fix: Add null check in ContractPickerVM
The ContractPickerPopup's SecurityMap binding source may produce null values
during normal operations (esp when opening/closing the popup, as the binding
source may depend on visuals that are initialized/destroyed when the popup
opens/closes).
2022-08-28 13:51:04 -05:00
John Colvin dee5f2684f fix: Add 'IsEnabledForegroundConverter' to ResourceDictionary
Bugs (fixed):
  * Client crashes when ladder settings dialog is opened
2022-08-28 13:21:27 -05:00
John Colvin f639a526cf refactor: Consolidate Co2 & md dirs into MarketData dir 2022-08-28 11:16:56 -05:00
Taha Afzal d168d8712e Added Keyed Theos that can be used to get theos from security ids 2022-08-25 11:58:54 -05:00
John Colvin 78a9605383 Update docker/linux
To get latest cmake
2022-08-24 01:34:38 -05:00
John Colvin a713b1018e fix (preemptive pnl): Actually use eq_comparer member
To determine when value changes occur (when to raise prop-changed event, etc.)
2022-08-23 16:54:31 -04:00
John Colvin 9f626dd10c ui (launcher): Use consistent margin between buttons 2022-08-23 16:54:31 -04:00
John Colvin 8ec7fdd60a ui (launcher): Remove pointless separator bar 2022-08-23 16:54:17 -04:00
John Colvin ffb2245ae6 refactor: Clean up immutable.pb.cs code-gen template a bit more
So the generated code more closely follows our formatting practices
2022-08-23 16:54:17 -04:00
John Colvin 21051c9a0b fix (pnl): Support Exp group popups filtering 2022-08-23 16:54:17 -04:00
John Colvin 1c8bd34144 ui (launcher): Remove pointless Help button 2022-08-23 02:29:05 -04:00
John Colvin f614fb7e7d ui (pnl): Indicate 'has day trades' w/ check mark
Instead of 'Yes/No'
2022-08-22 17:10:03 -04:00
John Colvin b222cd3e55 ui (pnl): Drop border between group/section headers
It needlessly clutters the ui, since the contrasting backgrounds already
illustrate the distinction
2022-08-22 16:55:18 -04:00
John Colvin 4f2be64813 ui: Rename 'P&L' -> 'P&L Summary', 'Day P&L' -> 'P&L Day Fills' 2022-08-22 16:43:31 -04:00
John Colvin bfb73ffc5a refactor: Add 'Freeze' prop to BTSBrushExtension 2022-08-22 16:08:40 -04:00
John Colvin 9bb7025752 fix: Don't share nonfrozen Brushes across threads
Bugs (fixed):
  * Grid settings dialogs crash when multiple are opened on diff threads

  Cause: Brushes (and all Freezables) that haven't been frozen throw an ex when
  any Dependency Properties are accessed from a thread that isn't associated
  with their Dispatcher (i.e., the thread on which they were created).
2022-08-22 16:08:40 -04:00
John Colvin bbfbd0b691 ui (launcher): Drop 'Reports' from buttons in Analytics module
Also change 'Vol Surfaces' -> 'Vol Surface' to be consistent (dropping
'Reports' from the other buttons made them singular)
2022-08-22 11:41:10 -04:00
John Colvin 5628e96a90 ui: Speed up expand/collapse animation in settings dialogs 2022-08-22 10:03:28 -04:00
John Colvin ef517b7554 ui: Reduce column resize-grip width
It blocks too much of the column filter's clickable area
2022-08-22 01:46:01 -04:00
John Colvin ba06af327d ui (slide, combo): Drop ':' in last trade desc 2022-08-22 01:30:31 -04:00
John Colvin b8b03172bc ui (slide): Display vol save & update times adjacently 2022-08-22 01:30:31 -04:00
John Colvin fb5c3c1e6e fix (orderbook-panel): Stretch visible items to fill dead space
Clean up the OrderBookView's VisualState's a bit in the process. Set each
item's visibility to 'Collapsed' by default, and flip to 'Visible' in the
VisualStates
2022-08-22 01:30:31 -04:00
John Colvin faaa7b11d4 fix (orderbook-ladder): Auto scroll to selected order
This used to work, not sure when it broke
2022-08-22 01:30:31 -04:00
John Colvin 92a0467e1e fix (orderbook-ladder): Detect LadderVM changes w/ default Equals
Bugs (fixed):
  * OrderBook ladder doesn't show orders
  * OrderBook ladder doesn't allow user to scroll beyond initial price range

  Cause: Both bugs occur because the LadderVMContainer doesn't detect LadderVM
  instance changes unless LadderVM.security has changed
2022-08-22 01:30:31 -04:00
John Colvin 3bb2025ea2 fix (ladder): Make sure price-range 'busy' is flipped back to false
Once the async price-range-shift op is completed
Bugs (fixed):
  * Can't scroll beyond initial price range in orderbook ladder

  Cause: The LadderGridHost's price-range-shift 'busy' flag gets stuck to false
2022-08-22 01:30:31 -04:00
John Colvin f2730ff0d7 doc: Add documentation for Task.ignore ext 2022-08-22 01:30:31 -04:00
John Colvin 7fcff9e5b4 refactor: Clean up MarketViewAnimation code a bit 2022-08-22 01:30:31 -04:00
John Colvin 51f83f4880 refactor: Rename 'HashCode.with' -> 'with_values'
Repurpose 'with' to accept a single value
2022-08-22 01:30:31 -04:00
John Colvin 88cb510aea refactor: Remove the ulong 'lldatetime' ext
It's too esoteric. Most ulongs don't represent an 'LLDateTime'
TODO: Consider removing the uint 'argb' extensions for same reason
2022-08-22 01:30:14 -04:00
John Colvin 452c642af0 refactor: Rename TryFirst ext FirstOrNull
Also move to it from APIExtensions to EnumerableExtensions
2022-08-22 00:05:08 -04:00
John Colvin 3fafc5004e refactor: Clean up LazySubscription, move to Spark.Core.Disposables ns 2022-08-22 00:05:07 -04:00
John Colvin fd8e502140 refactor: Lock private obj (not 'this')
'Lock(this)' is generally bad practice. It's better to use an explicitly named
var that is minimally accessible to outside callers to reduce risk of deadlocks.
2022-08-22 00:05:07 -04:00
John Colvin b499a5c38b refactor: Move IDisposable utils to Spark.Core.Disposables ns
* Move Anonymous/FinalizableDisposable to own file
* Rename DisposableCombo -> ImmutableDisposable and move it to its own file
* Clean up IDisposable utils impl, but keep changes to calling code minimial
2022-08-22 00:05:04 -04:00
John Colvin 2320383b16 refactor: Remove DisposableContainer class
It's innately antithetical to the Dispose pattern, as it can never truly be
disposed
2022-08-22 00:03:11 -04:00
John Colvin 59b3e73330 fix: Assign IDisposable to _dispose member (not local var)
So it is properly disposed, and not just eventually collected by GC
2022-08-22 00:03:11 -04:00
John Colvin 9d9a1b86c4 fix: Fix typo in 'init_auto_login'
The 'SubscribeClosed' call should be executed immediately, and the returned
IDisposable disposed when 'login_hooks' is disposed (prior to this commit, it
wasn't calling 'SubscribeClosed' until login_hooks was disposed)
2022-08-22 00:03:11 -04:00
John Colvin 21cc2cefbf refactor: Un-nest SelectorWrapper class, rename SelectorList 2022-08-22 00:03:11 -04:00
John Colvin 904df4260d fix (preemptive): Fix typo in SelectorWrapper list
Bugs (fixed):
  * [preemptive] SelectorWrapper.IsReadOnly is wrong

  Details: The fix is considered 'preemptive' because this prop is almost
  certainly not referenced. Nevertheless, the impl ought to be correct.
2022-08-22 00:03:11 -04:00
John Colvin af785d5d0b fix: Make sure ThreadSafeEvent uses same lock as owner 2022-08-22 00:03:11 -04:00
John Colvin 1d796856ca refactor: Make spark_api depend on spark_core (not other way around) 2022-08-22 00:03:11 -04:00
John Colvin 35f0d5a53f refactor: Split (Equality)Comparer utils up into modular classes 2022-08-22 00:03:10 -04:00
John Colvin 2b2fdd2b94 refactor: Remove borderline useless TaskExtensions
There were few references to these extensions, and many weren't referenced at all
2022-08-22 00:03:10 -04:00
John Colvin 9e4539a902 refactor: Remove unused code 2022-08-22 00:03:05 -04:00
John Colvin a76c8ffd98 fix: Fix typo 'is not null' -> 'is null'
Bugs (fixed):
  * Window size isn't restored if window has multiple tabs

  Cause: The typo flips the bool arg that indicates whether or not a window
  should be measured and fit to size (as happens when a window is opened for
  the first time)
2022-08-18 16:17:22 -04:00
John Colvin d7474cb8da fix (ui): Await settings-save before disposing IShellWindow
Bugs (fixed):
  * Can't reopen Fills windows via undo/redo in the BookMarks module

  Details:
    * Only applies to Fills windows closed via the tab-close 'x' button (not
      the window-close 'x' button)

    * Doesn't cause a crash, nor exhibit any side effects (aside from breaking
      undo/redo)

  Cause:
    * ISlow/SharedWindows (i.e., shell windows that run on bg threads) are
      disposed before the ISettingsCollector retrieves their state via
      'IShellWindow.SaveState'. The FillsWindow sets its _vm member to null
      when it is disposed, leading to a null-ref ex in its SaveState getter.
      This ex is caught (synchronously) and logged as an error, which explains
      the lack of side effects.
2022-08-18 13:57:44 -04:00
John Colvin 890a23a537 refactor: Rename AsyncEvent.invoke -> Invoke
To be syntactically consistent w/ csharp delegates (and the wpf Dispatcher,
which has Invoke/InvokeAsync methods)
2022-08-18 12:39:57 -04:00
John Colvin ab17eee260 refactor: Remove unused code 2022-08-18 12:39:57 -04:00
Taha Afzal acadc3bd7c Fixing merge conflict 2022-08-17 20:26:23 -04:00
Taha Afzal 8701fb7132 Fixing qty in ExchangeOpenOrders for fractional qty orders 2022-08-17 14:12:23 -04:00
Taha Afzal 89fcb3092b Fixing merge conflict 2022-08-17 12:54:27 -04:00
John Colvin c9856b96ae fix build (client): Remove erroneous using statement 2022-08-16 21:12:49 -04:00
John Colvin 04477a4b7c refactor: Don't copy strings 2022-08-16 21:08:53 -04:00
John Colvin 99371a2ead feat: Add Open Orders window 2022-08-16 17:25:03 -04:00
John Colvin 70487a8ef7 ui: Make 'B/S' the standard header for 'Side' cols
Until now, this header was hardcoded in OrderBookSettings
2022-08-16 17:25:03 -04:00
John Colvin 44c419fdaf refactor: Move bool-check converter from rec rep to common place
Will be used in the new Open Orders window
2022-08-16 17:25:03 -04:00
John Colvin 5eb151f9a0 refactor: Move common orderbook col headers to shared place
Specifically, col headers that will be used in the new Open Orders window, for
consistency's sake
2022-08-16 17:25:03 -04:00
John Colvin 855a939c51 refactor: Return obj from Log.not/isnull fns
For convenience, so these calls may be used in a chain like manner, etc.
2022-08-16 17:25:03 -04:00
John Colvin 7071d9b961 refactor: Add Not/MaybeNull attributes to Log.not/isnull fns
So the compiler recognizes these methods guarentee a particular result of
the expression 'obj is null'
2022-08-16 17:25:03 -04:00
John Colvin adf14491bc refactor: Check if obj is of type 'T' in Optional<T>.Equals 2022-08-16 17:25:03 -04:00
John Colvin 7e0e8f2801 refactor: Clean up Optional<T> 2022-08-16 17:25:02 -04:00
John Colvin 4a37e2d6a6 refactor: Implement IKeyedData in generated cs pbuf types
For convenience, so we don't have to pass key-selector lambdas all over the
place when dealing w/ IObservable<TableUpdate>s from the pbuf services
2022-08-16 17:25:02 -04:00
John Colvin 12b2371a69 style: Clean up api code-gen template immutable.pb.cs 2022-08-16 17:25:02 -04:00
John Colvin c19d173983 refactor: Move SecurityStore to spark_core, rename Resolver 2022-08-16 17:25:02 -04:00
John Colvin 203164f372 fix (preemptive): Init default UserSettings.day_fills_grid
This fix is preemptive because the hardcoded Day Fills defaults are automatically
used when the UserSettings.day_fills_grid member is null
2022-08-16 17:25:02 -04:00
John Colvin 6f69f1c2e2 fix (preemptive): Apply Day Fills settings migration rules
This is a preemptive fix bc as of now (8/14/2022), there are no Day Fills
migration rules
2022-08-16 17:25:02 -04:00
John Colvin ad1a585b5c refactor: Move Optional into Spark.Core 2022-08-16 17:25:02 -04:00
John Colvin f29e367ec7 refactor: Clean up ObservableSortedCollection
* Enable nullability
* Run formatter
* Add readonly specifiers where possible
* Improve documentation
2022-08-16 17:25:02 -04:00
John Colvin 18127383f0 refactor: Make IObservableCollection inherit IReadOnly 2022-08-16 17:25:02 -04:00
John Colvin b450c757c9 refactor: Move ObservableSortedCollection to Spark.Core.Collections 2022-08-16 17:25:02 -04:00
John Colvin 836683bcbe refactor: Move IObservableCollection to Spark.Core.Collections 2022-08-16 17:25:02 -04:00
John Colvin c271af30d8 refactor: Get rid of non-generic InsertRange ext 2022-08-16 17:25:02 -04:00
John Colvin 31fab94208 refactor: Get rid of non-generic AddRange ext
Most references to this fn were by generic IList<T>s. This resulted in error
prone, misleading code as such calls subtly bypass the compile-type type
constraints provided of the generic impl.
2022-08-16 17:25:02 -04:00
John Colvin a9b5067d7a refactor: Move fns from GlobalExtensions to less vague classes 2022-08-16 17:25:01 -04:00
John Colvin 7a31b025a2 refactor: Add 'ms' suffix to exch-open-order timestamp fields
Just to make it clear that they are milliseconds (not nanos, micros, etc.)
2022-08-16 17:24:52 -04:00
John Colvin 31897a1b2e refactor: Change exch-open-order record_id to auto-incremented int
To insulate ourselves from potential duplicate-id bugs at the exchange
2022-08-16 16:46:47 -04:00
John Colvin f93bc592cb fix: Set RetrievedExchangeOpenOrder.exchange_order_id
Bugs (fixed):
  * The 'exchange order id' field is empty in open orders data received
    by client
2022-08-16 13:22:38 -04:00
John Colvin 6ca2753951 fix (vs): Use precison in terms of actual data for eq comp
Bugs (fixed):
  * The tick up/down buttons have no effect for vol input cells

  Cause: The cell vm ignores some value updates because the equality
  comparer incorrectly considers the new value equal to the current one
  (because it doesn't use enough decimal places in the comparison)
2022-08-11 01:33:43 -04:00
Taha Afzal 470ca0093e Adding more logging helpers to VolSurfaceTroubleshootingFunctions 2022-08-10 20:54:10 -04:00
John Colvin 7e1715964f fix (vs): Pass the vm's 'current_grid' to the model
Bugs (fixed):
  * Cannot edit volsurface cell values (they are immediately reverted)

  Cause: The vm was passing the model's grid back to itself before, effectively
  undoing manual edits in cells
2022-08-10 18:27:41 -04:00
John Colvin 39e929a614 fix: Actually use eq-comp member in Property vm 2022-08-10 18:17:58 -04:00
John Colvin a9aa06f275 fix (vs): Actually use coulmn comparer in cell vm 2022-08-10 18:11:27 -04:00
John Colvin 54510c9e59 refactor (vs grid): Supress recalc reqs while processing update 2022-08-10 14:26:28 -04:00
John Colvin cb56429f04 refactor: Rename 'execute' -> 'Invoke'
To be consistent and interchangeable w/ System.Action
2022-08-10 14:26:28 -04:00
John Colvin ac8147cc0f refactor: Add 'implicit operator T(Optional<T>)' for convenience 2022-08-10 14:26:28 -04:00
John Colvin 82ac189ac9 refactor: Strip 'Wrapper' from 'DeferrableActionWrapper' name 2022-08-10 14:26:27 -04:00
John Colvin 5721ff78b6 fix (vs): Only request recalc when input changes (not output)
Bugs (fixed):
  * The volsurface grid can get into an endless loop of recalc requests
2022-08-09 15:56:05 -04:00
John Colvin 7afd2947f1 refactor: Clean up vs grid vms a bit
* Split vs-cell-vm classes up into own files
* Rename classes by changing 'VolGrid' prefix to 'VolSurface'
* Remove unused struct VolSurfaceCellState
* Enable nullable
* Run formatter
2022-08-09 15:55:40 -04:00
John Colvin c3e3862c5f refactor: Update vs cell 'is_dirty' synchronously when vals change 2022-08-09 02:57:35 -04:00
John Colvin bf2dc9ecca fix (vs grid): Account for nan & rounding error
Bugs (fixed):
  * The volsurface grid starts flasing is_dirty borders all over the place. The
    repro is inexact, but it seems to happen after inputs are changed a few
    times (perhaps from loading a previous volsurface).

  * The volsurface grid flashes is_dirty borders just from clicking on an input
    cell (even if no change is entered).
2022-08-09 02:57:35 -04:00
John Colvin e0e188a02c refactor: Enable NaN identity equality in tick_equals 2022-08-09 02:57:35 -04:00
John Colvin 79ba1654d3 fix: Fix typo in tick_equals fn 2022-08-09 02:57:35 -04:00
Taha Afzal 2aab0d18a5 Formatting slide exp, to look like PNL's 2022-08-08 23:45:02 -04:00
John Colvin 312c8ded11 fix (ui pnl): Add greek props to group row vm
Bugs (fixed):
  * Greek sums still aren't visible in group rows (though they are visible in
    Selected/Total header rows)
2022-08-08 16:11:25 -04:00
John Colvin 3f86779da6 ui (launcher): Move PNL menu items to Analytics module 2022-08-08 16:11:25 -04:00
John Colvin 716d3b8482 ui (day fills): Make title & icon consistent w/ PNL win 2022-08-08 16:11:25 -04:00
John Colvin 24f6dbc4f0 ui (day fills): Convert fill_time utc to local 2022-08-08 16:11:25 -04:00
John Colvin 3e943fa35e refactor (pnl): Add 'PNL' prop to Icons class
To make it clear which icon belongs to which window
2022-08-08 16:11:25 -04:00
John Colvin 457f878b41 ui (pnl): Change win title to 'P&L' to match launcher menu item 2022-08-08 16:11:25 -04:00
John Colvin ac2b2d042a refactor: Split WorkspaceProtos up into 1 class/file 2022-08-08 16:11:25 -04:00
John Colvin 829d2cdbf6 refactor: Provide ICloneable impl in IProtobuf<T> 2022-08-08 16:11:25 -04:00
John Colvin 3cd9693b36 diag (vs): Log cell vm 'is_dirty' changes 2022-08-08 16:11:25 -04:00
John Colvin 2b52ecf2ef perf (vs): Supress repeated 'is_dirty' updates
Before the updates reach the dispatcher thread
2022-08-08 16:11:25 -04:00
John Colvin faab60cbc1 ui (vs): Convert NaN to 0 when users clicks tick up/down 2022-08-08 16:11:25 -04:00
John Colvin b6be0d649d fix (vs): Don't throw ex if parse_double input is null
Bugs (fixed):
  * Previous vol surfaces may have missing data, which can lead to an assert
    crash in the parse_double fn
2022-08-08 16:11:25 -04:00
Taha Afzal 2a65c45d21 Theos/Greeks are still produced if AW2 window is not loaded 2022-08-08 16:00:48 -04:00
Taha Afzal dc6ae2ac29 Removing P from the names of greek columns in Day PNL 2022-08-08 11:53:56 -04:00
Taha Afzal df4250c33a Hooking AW2 populate empty exps 2022-08-07 22:03:50 -04:00
John Colvin 53504ef6f0 ui (pnl): Improve default settings 2022-08-07 15:18:16 -04:00
John Colvin 10afb1af06 ui (pnl): Show greek sums in group/header rows 2022-08-07 14:59:00 -04:00
John Colvin a9149dfa87 refactor: Clean up PNLNormalizedData
* Use new lang feats: nullable, and 'init' prop setters
* Group 'sod', 'day', and 'working' members in respective groups
* Run formatter
2022-08-07 14:39:44 -04:00
John Colvin 5afa6695e7 fix (pnl view): Enforce min height for 'Selected' header row 2022-08-07 13:51:55 -04:00
John Colvin d2a6d54090 refactor (pnl): Replace dyn resources w/ Bindings in xaml
Traditional Bindings are more performant than DynamicResources, and make for
cleaner code
2022-08-07 13:51:55 -04:00
John Colvin 794ac25c01 log: Change 'Begin/End' tags to 'BEG/END' in log_op ext
Improves readability of log_op logs

* Gives the 'BEG/END' tags a uniform width, so their msg bodies will align
* All caps makes the tags stand out

Improves readability by providing uniform width to the BEG/END tags
2022-08-07 13:51:55 -04:00
John Colvin 37214e9480 refactor: Make msg body param optional in 'fn' logger exts 2022-08-07 13:51:55 -04:00
John Colvin 90ab551778 ui (day fills): Format dates in exp col filter 2022-08-07 13:51:54 -04:00
John Colvin 9a4ec46440 fix: Don't begin shutdown til after workspace saved (async)
Bugs (fixed):
   * Seems like only one window's settings are restored w/ workspace
2022-08-07 13:51:54 -04:00
John Colvin c86d283755 fix: Supress empty TableUpdates in 'distinct_on'
Bugs (fixed):
  * Discrete values column filters (i.e., multi-selector views) that are driven
  by 'distinct_on' IObservable<TableUpdate> deselect items when the main
  grid data changes

  Cause: When processing updates from the input IObseravble, the 'distinct_on'
  ext doesn't check if the new/old results are equal. This in turn causes the
  selector-view to remove, then re-add items that didn't actually change.
  Exhibiting reasonable behavior, the view deselects items when they are removed
  from the ItemsSource.
2022-08-07 13:51:54 -04:00
John Colvin 941956c1b5 fix: Actually supress false changes in 'to_table_checked' ext 2022-08-07 13:51:54 -04:00
John Colvin 67e3d22104 style: Fix typo in param name '_selector' -> 'selector' 2022-08-07 13:51:54 -04:00
John Colvin 7e41c93f9a refactor: Rename PNLFilterStates -> PNLFilterSettings 2022-08-07 13:51:54 -04:00
John Colvin 086ccbb3fa refactor: Weaken T constraint for is_within_range ext
There is no reason T has to implement IFloatingPoint<T>
2022-08-07 13:51:54 -04:00
John Colvin 329ddc576d ui (day fills): Add (groupable) exp column 2022-08-07 13:51:54 -04:00
John Colvin 1faef425ab refactor: Consolidate format_expiration fns into single fn 2022-08-07 13:51:54 -04:00
John Colvin bb068cf6b2 fix (preemptive): Add 'Option' case to exp switch expr 2022-08-07 13:51:54 -04:00
John Colvin f7cade41c6 ui (day fills): Fmt qty cols w/ sec-meta display settings 2022-08-07 13:51:54 -04:00
John Colvin 47afd3a911 ui (day fills): Hide bid/ask cols by default 2022-08-07 13:51:54 -04:00
John Colvin ef80d2a41d ui: Shorten a few default column widths
Namely: Account, Exchange, and Symbol
2022-08-07 13:51:53 -04:00
John Colvin 44ef080e9f ui (day fills): Format theo and driver w/ 4 dec places
With the caveat that future fills' drivers are formatted according to their own
tick factors (i.e., same as the "price" column). This should be good/reasonable
behavior because in rare cases where futures don't drive themselves, they are
most likely driven by a neighboring expiration with the same price display.
2022-08-07 13:51:53 -04:00
John Colvin fef8d2c413 ui (day fills): Format price w/ sec's tick factors 2022-08-07 13:51:53 -04:00
John Colvin 201746e561 fix (day fills): Init column models w/ settings
Bugs (fixed):
  * Day fills column settings are not restored with workspace

  Cause: This is a kind-of re-entrancy bug.  When the SimpleGridSettingsManager
  attempts to load the initial column settings, it assigns props in the column
  views. When the width prop is set, the column view forwards the new width to
  the model, which causes the model to fire a settings_changed event, which
  pipes the model's settings (which have not been fully initialized) back to
  the view.
2022-08-07 13:51:53 -04:00
John Colvin 8e375a0b7f ui (day fills): Use qty fg to indicate fill side
Rather than using the row bg, this gives the win a subtler, more modern look
2022-08-07 13:51:53 -04:00
John Colvin 045f3dc060 chore: Move ValueConverter into own file 2022-08-07 13:51:53 -04:00
John Colvin 6b6012236d ui (day fills): Add pnl, delta foreground triggers 2022-08-07 13:51:53 -04:00
John Colvin 9cee798939 chore: Set ModalStateDefinition ContentProperty
For convenience in xaml (so ModalStateDefinition.Source can be defined without
explicit tag)
2022-08-07 13:51:53 -04:00
John Colvin c79bdb12e0 refactor: Make ActivityLogCategories readonly props 2022-08-07 13:51:53 -04:00
John Colvin bce77d65de fix: Add null check in OptionsView
Bugs (fixed):
  * If an Options View window is launched w/ "incomplete" security criteria
    (i.e., not a tuple of Exch, Type, Sym), a null ref crash happens when the
    window is restored with the workspace.
2022-08-07 13:51:53 -04:00
John Colvin 0db814ef2d 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-08-07 13:51:53 -04:00
John Colvin 31b5ec4bd3 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-08-07 13:51:52 -04:00
John Colvin e15cdfd76e 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-08-07 13:51:52 -04:00
John Colvin eb150ba82c chore (ui): Hook up background setting in OrderTypeColumn 2022-08-07 13:51:52 -04:00
John Colvin d763275179 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-08-07 13:51:52 -04:00
John Colvin 2b96a8a5c4 ui: Enable grid background setting in all windows
And remove bool props that were used to toggle this behavior
2022-08-07 13:51:52 -04:00
John Colvin 31866c76b7 chore (vs graph): Add tick_line_color setting 2022-08-07 13:51:52 -04:00
John Colvin a2da946e03 fix (vs graph): Actually use axis_line_color setting in vm
Bugs (fixed):
  * The vs graph axis line color setting is ignored
2022-08-07 13:51:52 -04:00
John Colvin 528bab34e7 chore: Show color name in ColorNotFoundException msg 2022-08-07 13:51:52 -04:00
John Colvin 776b9e4f94 chore: Remove '_color' and '_brush' props from BTSColors
The BTSColor props are implicitly convertible to both System.Windows.Media.Color
and Brush
2022-08-07 13:51:52 -04:00
John Colvin 168d328e97 chore: Clean BTSColorExtension 2022-08-06 23:54:15 -04:00
John Colvin f871dbd230 chore: Add 'Pure' attr to is_null_or_empty ext 2022-08-06 23:54:15 -04:00
John Colvin 1662b56ea0 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-08-06 23:54:15 -04:00
John Colvin f3302dbac0 fix (ui): Validate width/height before updating DragRectAdorner 2022-08-06 23:54:15 -04:00
John Colvin 181072f3e7 chore: Clean up ui settings classes
* Move most settings files into new dir 'Model/Settings'
* Conform code style to our current practices
2022-08-06 23:54:15 -04:00
John Colvin f654312123 chore (refactor): Move synth mgmt settings classes into sep files 2022-08-05 13:41:37 -04:00
John Colvin c46d97646a 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-08-05 13:41:37 -04:00
John Colvin 41742359e9 fix (vs ui): Don't clip vs time sched ui 2022-08-05 13:41:37 -04:00
John Colvin 024723925e ui (vs grid settings): Constrain window height 2022-08-05 13:41:37 -04:00
John Colvin 76b834768e style: Clean up spark.csproj 2022-08-05 13:41:37 -04:00
John Colvin 89284bea87 build: Upgrade csharp nuget pkgs 2022-08-05 13:41:37 -04:00
John Colvin 532154640b refactor: Replace PNLCellAppearance ctr w/ 'init' props 2022-08-05 13:41:36 -04:00
Taha Afzal ab8468d498 Added function in VolSurfaceDisplayModel to populate empty exps 2022-08-04 18:42:15 -04:00
Taha Afzal 84b0332778 Better logs for the case when Deribit's open orders's security can not be resolved 2022-08-03 23:53:57 -04:00
Taha Afzal 20b601f290 Fixed the crash related to querying Deribit for open orders 2022-08-03 16:57:10 -04:00
Taha Afzal 47002cae4c This PNL fix change was accidentally merged out 2022-08-03 08:47:50 -04:00
John Colvin eaaffe369a Fix typo typeof(HyperlinkCell) -> typeof(TextCell) 2022-08-03 00:07:39 -04:00
John Colvin 7292a31c00 fix (rec rep): Save grid settings w/ workspace 2022-08-03 00:07:39 -04:00
John Colvin 389d762a93 ui (launcher): Drop "2" in "P&L 2" menu item
It was leftover from the transition to the "new" pnl window (which hasn't been
new since 2019)
2022-08-03 00:07:39 -04:00
John Colvin 9704ebf096 style: Move ReconcileReportModel into rec rep dir 2022-08-03 00:07:39 -04:00
John Colvin de320338ca ui (launcher): Group 'Fill' menu items together 2022-08-03 00:07:39 -04:00
John Colvin 668dfd9130 feat (ui): Add Day Fills win 2022-08-03 00:07:39 -04:00
John Colvin a2960b23a8 refactor (ITradeLogRow): Rename trader -> user, add user_id
Use consistent nomenclature throught the sys
2022-08-03 00:01:02 -04:00
John Colvin 55744edc25 refactor: Move SecurityDataHelper.Defaults into Security class 2022-08-02 13:24:48 -04:00
John Colvin 7ece5d18cb refactor: Move sec 'key_fn' into Security class 2022-08-02 12:37:46 -04:00
John Colvin 8005ac8635 refactor: Name top_of_book tuple items bid/ask 2022-08-01 21:56:07 -04:00
John Colvin c00a71fdfa chore: Add fill_kind to ITradeLogRow 2022-08-01 11:14:29 -04:00
John Colvin 197c915968 Remove erroneous font_size binding in xaml
Each cell's font size comes from its associated column object (not the cell vm)
2022-08-01 11:14:29 -04:00
John Colvin 6d77a07bbe fix: Load grid-level settings in pnl window
Font family/size/weight, foreground, background
2022-08-01 11:14:29 -04:00
John Colvin adfb560dd1 chore: Post users-map on the bus 2022-08-01 11:14:29 -04:00
John Colvin 508d20e4e0 refactor: Rename ITradeLogRow.trade_key -> order_key
This is what it actually is; the trade_key misnomer was ported from edge
2022-08-01 11:14:29 -04:00
John Colvin 72457619f7 chore: Move IPositionModel to Spark.Trading ns 2022-08-01 11:14:29 -04:00
John Colvin 18d5b83a95 chore: Replace anon pnl win w/ proper PNLWindow class
The PNL window is too complex/terse to be nested anonymously in the
PNLWindowFactory class.  This makes the code cleaner/easier to read.
2022-08-01 11:14:29 -04:00
John Colvin 653362b947 chore: Make 'Safe' IEnumerable exts accept nullable ref types 2022-08-01 11:14:29 -04:00
John Colvin b7477b8f93 fix (fills ui): Add back 'Fill Status' col
Not sure when/why it went missing
2022-08-01 11:14:29 -04:00
John Colvin 105f1fceaf ui (pnl): Increase sec column default width 2022-08-01 11:14:29 -04:00
John Colvin cb65489ab7 fix (combo vm): Fix typo when assigning swipe_sum net/calls/puts
Bugs (fixed):
  * The swipe sum net/puts are swapped in combo status bar
2022-08-01 11:14:29 -04:00
John Colvin 96772727df fix (exp params): Ensure auto-picked driver has right sym 2022-08-01 11:14:29 -04:00
John Colvin 960a618fe1 fix: Bind pnl account col to AccountTuple
Bugs (fixed):
  * The group-row pnl cell hyperlinks don't open anything when clicked

  Cause: An InvalidCastException is thrown when the code that creates the fills
  vm (for the popup) casts 'PNLRowCollectionViewGroup.Name' to an AccountTuple,
  as said 'Name' member is bound to the 'account_name' (of type string).
2022-08-01 11:14:29 -04:00
John Colvin 505cd37225 chore: Assert that PositionPriceSize.GetHashCode isn't invoked
Impl doesn't guarentee equal objects produce the same hash
2022-08-01 11:14:28 -04:00
John Colvin a5f66b8ac6 feat: Add greeks cols to pnl view (for options) 2022-08-01 11:14:28 -04:00
John Colvin 2021f29f62 feat: Support options in pnl view 2022-08-01 11:14:28 -04:00
John Colvin 9ccf3e0f87 chore: Remove UTF-8 BOM from pnl files 2022-08-01 11:14:28 -04:00
John Colvin 7cfc53eba8 refactor: Make sum_real ext generic (IFloatingPoint<T>)
Also add bool param 'nan_if_none' (to return NaN instead of 0 when values
contains no real numbers)
2022-08-01 11:14:28 -04:00
John Colvin f9d269c750 chore: Add account_id to ITradeLogRow, IPNLUnit 2022-08-01 11:14:28 -04:00
John Colvin 67d5161fd1 chore: Dispose _pnl_calc in ReportDaemon.Dispose
This wasn't causing any problems in practice (this class is instantiated once
on startup and never gets disposed).  However, since it implements IDisposable,
might as well do it correctly.
2022-08-01 11:14:28 -04:00
Taha Afzal d6e9bbce71 Something funky, not sure why it is showing as touched 2022-08-01 11:14:28 -04:00
John Colvin 76ec2c0fa2 fix: Pass key_fn to TableUpdate Operate ext
Bugs (fixed):
  * PNL window crashes immediately when opened

    Cause: The 'Operate' ext fn aggregates an IObservable of TableUpdates w/
    another IObservable of any T.  If the latter fires before the former, an
    'empty' TableUpdate is passed to the aggregate fn.  When this happens, a
    null ref ex is thrown in the 'empty' TableUpdate's ctr because the key
    param is null.
2022-08-01 11:14:28 -04:00
Taha Afzal e82a2c9402 Added Day PNL trades to PNLData 2022-08-01 11:14:28 -04:00
Taha Afzal 60ce106e24 Fixing a PNL crash which was caused by options for a symbol being temporarily null 2022-08-01 11:14:28 -04:00
Taha Afzal 1eb4952422 Added Control Keys to sheets, Ctrl + right click always brings up the context menu, Ctrl + market always brings up the ladder 2022-08-01 11:14:28 -04:00
Taha Afzal 3043582889 Improved some log messages 2022-08-01 11:14:28 -04:00
Taha Afzal f604db6517 Reorganized PNL calculator and associated types 2022-08-01 11:14:28 -04:00
Taha Afzal f95b0c19d7 Added PNL Calculation code 2022-08-01 11:14:28 -04:00
taha afzal 655bf87e92 Fixing open orders callback (was firing intermittent callbacks) 2022-07-22 16:36:52 -04:00
taha afzal 6d06a1920d OrderServiceServer now publishes open orders 2022-07-22 15:16:03 -04:00
taha afzal 70af51e163 ExchangeOpenOrders are now routed all the way to OrderServiceServer 2022-07-21 20:36:17 -04:00
taha afzal 2c17fe334e Added Exchange Open Orders function to IExecutionGateway 2022-07-21 00:38:15 -04:00
taha afzal 5eca2cd3ac Exchange Open orders are routed all the way to EMExecutionGateway 2022-07-20 20:13:56 -04:00
taha afzal 4b5ff8cad4 Adding AsyncRequestHelper to EmMDListener, that allows code to be shared bw positions and open_orders request 2022-07-20 15:29:25 -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
John Colvin 258d4a3fc1 import compute_synthetic_book method from spartan 2020-12-08 23:00:18 -06:00
John Colvin c53f6425cd import IntPrice arithmetic operators from spartan
The compute_synthetic_book method (also to be imported
from spartan) depends on a couple of them.
2020-12-08 22:52:28 -06:00
1815 changed files with 117165 additions and 72527 deletions

No files matched your search

+18
View File
@@ -7,6 +7,24 @@
"commands": [
"dotnet-format"
]
},
"fable": {
"version": "4.0.0-theta-018",
"commands": [
"fable"
]
},
"fantomas": {
"version": "5.2.2",
"commands": [
"fantomas"
]
},
"fake-cli": {
"version": "6.0.0",
"commands": [
"fake"
]
}
}
}
+3 -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
@@ -51,3 +50,4 @@ trace_data/
*.tmp/*
/.venv*/*
.cache/
src/web/api/tsconfig.*.g.json
-3
View File
@@ -7,6 +7,3 @@
[submodule "docker/windows"]
path = docker/windows
url = git@bitbucket.org:bluetradesys/windows_docker.git
[submodule "src/deribit-crypto-connector-demo-application"]
path = src/deribit-crypto-connector-demo-application
url = git@gitlab.com:cryptoexchanges1/deribit-crypto-connector-demo-application.git
+22 -3
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.12)
project(spark)
if(WIN32)
@@ -7,12 +7,18 @@ else()
set(platform "linux")
endif()
set(EXTERNALS_ROOT "${CMAKE_SOURCE_DIR}/externals/${platform}")
set(
EXTERNALS_ROOT
"${CMAKE_SOURCE_DIR}/externals/${platform}"
CACHE
STRING
"External dependencies root folder (should contain folders: lib, bin, include")
set(SPARK_PYTHON "${EXTERNALS_ROOT}/python")
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 +53,12 @@ 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_EXCHANGE_BINANCE)
add_compile_definitions(CCAPI_ENABLE_LOG_WARN)
# flags
set(
@@ -67,7 +79,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 +105,9 @@ else()
DEPENDS sparkd data_files_dir)
add_custom_target(server_layout ALL DEPENDS ${CMAKE_BINARY_DIR}/server)
install(DIRECTORY "${CMAKE_BINARY_DIR}/server/plugins" DESTINATION bin)
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()
-25
View File
@@ -1,25 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32630.192
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpreaderFrontEnd", "SpreaderFrontEnd\SpreaderFrontEnd.csproj", "{28EE9ABE-BBA6-4587-8BEB-3B0CD979ED22}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{28EE9ABE-BBA6-4587-8BEB-3B0CD979ED22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{28EE9ABE-BBA6-4587-8BEB-3B0CD979ED22}.Debug|Any CPU.Build.0 = Debug|Any CPU
{28EE9ABE-BBA6-4587-8BEB-3B0CD979ED22}.Release|Any CPU.ActiveCfg = Release|Any CPU
{28EE9ABE-BBA6-4587-8BEB-3B0CD979ED22}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3E2EF0DA-32BB-4A7A-9089-B132E1677AA7}
EndGlobalSection
EndGlobal
@@ -1,36 +0,0 @@
using System;
using System.Linq;
namespace SpreaderFrontEnd {
public class Book : IEquatable<Book> {
public Book(BookSide bids = null, BookSide asks = null) {
this.bids = bids ?? new BookSide();
this.asks = asks ?? new BookSide();
}
public BookSide bids { get; }
public BookSide asks { get; }
public Book Clone() {
return new Book(
new BookSide(bids.levels.ToList()),
new BookSide(asks.levels.ToList()));
}
public bool Equals(Book other) {
return other != null && other.bids.Equals(bids) && other.asks.Equals(asks);
}
public override bool Equals(object obj) {
return Equals(obj as Book);
}
public override int GetHashCode() {
return HashCodeHelper.combine(bids.GetHashCode(), asks.GetHashCode());
}
public override string ToString() {
return $"bid: {bids} | ask: {asks}";
}
}
}
@@ -1,38 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace SpreaderFrontEnd {
public class BookSide : IEquatable<BookSide> {
public BookSide() {
levels = new List<PriceLevel>();
}
public BookSide(IEnumerable<PriceLevel> levels) {
this.levels = levels?.ToList() ?? new List<PriceLevel>();
}
public IList<PriceLevel> levels { get; }
public BookSide Clone() {
return new BookSide(levels.ToList());
}
public bool Equals(BookSide other) {
return other != null && levels.SequenceEqual(other.levels);
}
public override bool Equals(object obj) {
return Equals(obj as BookSide);
}
public override int GetHashCode() {
return levels.Select(l => l.GetHashCode()).Skip(1).Aggregate(
levels[0].GetHashCode(), HashCodeHelper.combine);
}
public override string ToString() {
return string.Join("; ", levels);
}
}
}
@@ -1,120 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace SpreaderFrontEnd {
public class LegCursor {
public LegCursor(int leg_size, IList<PriceLevel> levels) {
this.leg_size = leg_size;
this.levels = levels;
}
/// <summary>
/// The [signed] quantity of this leg in the SpreaderContract to which it belongs
/// </summary>
public int leg_size { get; }
/// <summary>
/// The [unsigned] quantity of this leg in the SpreaderContract to which it belongs
/// </summary>
public int leg_size_abs {
get {
return Math.Abs(leg_size);
}
}
/// <summary>
/// The price levels of the underlying BookSide
/// </summary>
public IList<PriceLevel> levels { get; }
/// <summary>
/// The index of the current level. When <see cref="consume_unit_qty(uint, out List{PriceLevel})"/>
/// is called, quantity consumption begins at this level. Once this level's quantity is fully
/// consumed, <see cref="cursor"/> is incremented, and <see cref="curr_level_consumed_qty"/>
/// is reset to 0.
/// </summary>
public int cursor { get; private set; }
/// <summary>
/// The quantity that has been consumed at the current level (i.e., the level at index
/// <see cref="cursor"/>)
/// </summary>
public uint curr_level_consumed_qty { get; private set; }
/// <summary>
/// Consumes the specified quantity of units at the best available price(s)
/// </summary>
/// <param name="unit_qty">
/// The unit quantity to consume
/// </param>
/// <returns>True if the entire quantity is consumed, otherwise false.</returns>
public bool consume_unit_qty(uint unit_qty, out List<PriceLevel> consumed_levels) {
consumed_levels = new List<PriceLevel>();
uint marg_qty = (uint)(unit_qty * leg_size_abs);
var consumed_qty = _consume_raw_qty(marg_qty, ref consumed_levels);
Debug.Assert(consumed_qty % leg_size_abs == 0);
uint consumed_units = (uint)(consumed_qty / leg_size_abs);
return consumed_units == unit_qty;
}
/// <summary>
/// Gets the number of units (raw_quantity / leg_size_abs) available at the best price
/// </summary>
public PriceLevel curr_synth_level() {
if (cursor >= levels.Count) {
return PriceLevel.empty;
}
var curr_level = levels[cursor];
Debug.Assert(curr_level.qty >= curr_level_consumed_qty);
var curr_level_rem_qty = curr_level.qty - curr_level_consumed_qty;
if (curr_level_rem_qty >= leg_size_abs) {
return new PriceLevel(
price: curr_level.price * leg_size_abs,
qty: (uint)(curr_level_rem_qty / leg_size_abs));
}
double unit_cost = curr_level.price * curr_level_rem_qty;
var unit_rem = leg_size_abs - curr_level_rem_qty;
for (int i = cursor + 1; i < levels.Count; i++) {
curr_level = levels[i];
if (curr_level.qty >= unit_rem) {
unit_cost += curr_level.price * unit_rem;
return new PriceLevel(price: unit_cost, qty: 1);
}
unit_cost += curr_level.price * curr_level.qty;
unit_rem -= curr_level.qty;
}
return PriceLevel.empty;
}
/// <summary>
/// Consumes as much of the specified [raw] quantity as possible
/// </summary>
/// <returns>
/// The quantity that was actually consumed
/// </returns>
uint _consume_raw_qty(uint raw_qty, ref List<PriceLevel> dest) {
if (levels == null || cursor >= levels.Count) {
return 0;
}
var curr_level = levels[cursor];
// Cursor should be incremented when curr_level_consumed_qty == levels[cursor].qty
// (i.e., curr_level.qty should never be less than curr_level_consumed_qty)
Debug.Assert(curr_level.qty > curr_level_consumed_qty);
var curr_level_qty_rem = curr_level.qty - curr_level_consumed_qty;
if (curr_level_qty_rem > raw_qty) {
curr_level_consumed_qty += raw_qty;
dest.Add(new PriceLevel(price: curr_level.price, qty: raw_qty));
return raw_qty;
}
// The input qty is greater than the qty that remains at this level. Consume the rest on
// the next level.
cursor++;
curr_level_consumed_qty = 0;
dest.Add(new PriceLevel(price: curr_level.price, qty: curr_level_qty_rem));
return curr_level_qty_rem + _consume_raw_qty(raw_qty - curr_level_qty_rem, ref dest);
}
}
}
@@ -1,44 +0,0 @@
using System;
namespace SpreaderFrontEnd {
public struct PriceLevel : IEquatable<PriceLevel> {
public PriceLevel(double price, uint qty) {
this.price = price;
this.qty = qty;
}
public static PriceLevel empty {
get {
return new PriceLevel(double.NaN, 0);
}
}
public double price { get; }
public uint qty { get; }
public PriceLevel subtract_qty(uint value) {
System.Diagnostics.Debug.Assert(value <= qty);
return new PriceLevel(price, qty - value);
}
public PriceLevel add_qty(uint value) {
return new PriceLevel(price, qty + value);
}
public override string ToString() {
return $"{price} ({qty})";
}
public bool Equals(PriceLevel other) {
return qty == other.qty && price.Equals(other.price);
}
public override bool Equals(object obj) {
return obj is PriceLevel other && Equals(other);
}
public override int GetHashCode() {
return HashCodeHelper.combine(price.GetHashCode(), qty.GetHashCode());
}
}
}
@@ -1,49 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
namespace SpreaderFrontEnd {
public static class SpreaderBookCalculator {
public static Book compute_spreader_book(
SpreaderContract contract, IEnumerable<Book> leg_books) {
if (contract == null) {
throw new ArgumentNullException(nameof(contract));
}
if (leg_books == null) {
throw new ArgumentNullException(nameof(leg_books));
}
var leg_book_list = leg_books as IList<Book> ?? leg_books.ToList();
var synth_book = new SyntheticBook(contract, leg_book_list);
return synth_book.to_book();
}
public static BookSide compute_spreader_book_side(
SpreaderContract contract, IList<Book> leg_books, bool is_bid) {
Debug.Assert(contract.spread_legs.Count == leg_books.Count);
var leg_cursors = leg_books.Select((b, i) => new LegCursor(
contract.spread_legs[i].qty,
contract.spread_legs[i].qty < 0 == is_bid ? b.asks.levels : b.bids.levels)).ToList();
var level_qty = leg_cursors.Select(lc => lc.curr_synth_level().qty).Min();
var result = new BookSide();
while (level_qty > 0) {
double level_price = 0;
for (int i = 0; i < leg_cursors.Count; i++) {
var lc = leg_cursors[i];
bool did_consume = lc.consume_unit_qty(level_qty, out var consumed_levels);
Debug.Assert(did_consume);
var leg_cost = consumed_levels.Select(l => l.price * l.qty).Sum() / level_qty;
if (lc.leg_size < 0) {
level_price -= leg_cost;
} else {
level_price += leg_cost;
}
}
result.levels.Add(new PriceLevel(price: level_price, qty: level_qty));
level_qty = leg_cursors.Select(lc => lc.curr_synth_level().qty).Min();
}
return result;
}
}
}
@@ -1,17 +0,0 @@
using System.Collections.Generic;
namespace SpreaderFrontEnd {
class SyntheticBook {
public SyntheticBook(SpreaderContract contract, IList<Book> leg_books) {
bids = new SyntheticBookSide(contract, leg_books, true);
asks = new SyntheticBookSide(contract, leg_books, false);
}
public SyntheticBookSide bids { get; }
public SyntheticBookSide asks { get; }
public Book to_book() {
return new Book(bids: bids.to_book_side(), asks: asks.to_book_side());
}
}
}
@@ -1,28 +0,0 @@
using System.Collections;
using System.Collections.Generic;
namespace SpreaderFrontEnd {
class SyntheticBookSide : IEnumerable<PriceLevel> {
readonly SpreaderContract _contract;
readonly IList<Book> _leg_books;
readonly bool _is_bid;
public SyntheticBookSide(SpreaderContract contract, IList<Book> leg_books, bool is_bid) {
_contract = contract;
_leg_books = leg_books;
_is_bid = is_bid;
}
public BookSide to_book_side() {
return new BookSide(this);
}
public IEnumerator<PriceLevel> GetEnumerator() {
return new SyntheticBookSideEnumerator(_contract, _leg_books, _is_bid);
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
}
@@ -1,59 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Collections;
namespace SpreaderFrontEnd {
class SyntheticBookSideEnumerator : IEnumerator<PriceLevel> {
readonly List<LegCursor> _leg_cursors;
PriceLevel _current;
uint _level_qty;
public SyntheticBookSideEnumerator(
SpreaderContract contract, IList<Book> leg_books, bool is_bid) {
Debug.Assert(contract.spread_legs.Count == leg_books.Count);
_leg_cursors = new List<LegCursor>(leg_books.Count);
for (int i = 0; i < leg_books.Count; i++) {
_leg_cursors.Add(new LegCursor(
contract.spread_legs[i].qty,
contract.spread_legs[i].qty < 0 == is_bid ?
leg_books[i].asks.levels : leg_books[i].bids.levels));
}
}
public PriceLevel Current => _current;
object IEnumerator.Current => _current;
public void Dispose() { }
public bool MoveNext() {
_level_qty = _leg_cursors.Select(lc => lc.curr_synth_level().qty).Min();
if (_level_qty == 0) {
return false;
}
double level_price = 0;
for (int i = 0; i < _leg_cursors.Count; i++) {
var lc = _leg_cursors[i];
bool did_consume = lc.consume_unit_qty(_level_qty, out var consumed_levels);
Debug.Assert(did_consume);
var leg_cost = consumed_levels.Select(l => l.price * l.qty).Sum() / _level_qty;
if (lc.leg_size < 0) {
level_price -= leg_cost;
} else {
level_price += leg_cost;
}
}
_current = new PriceLevel(price: level_price, qty: _level_qty);
return true;
}
public void Reset() {
for (int i = 0; i < _leg_cursors.Count; i++) {
var lc = _leg_cursors[i];
_leg_cursors[i] = new LegCursor(lc.leg_size, lc.levels);
}
}
}
}
@@ -1,8 +0,0 @@
namespace SpreaderFrontEnd {
static class HashCodeHelper {
// Copied from https://referencesource.microsoft.com/#System.Numerics/System/Numerics/HashCodeHelper.cs
public static int combine(int h1, int h2) {
return (((h1 << 5) + h1) ^ h2);
}
}
}
-744
View File
@@ -1,744 +0,0 @@
using System.Windows.Forms;
namespace SpreaderFrontEnd
{
partial class LegControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this._combobox_security = new System.Windows.Forms.ComboBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this._textbox_quote_qho_length = new System.Windows.Forms.TextBox();
this._textbox_quote_insidemarketdistance_towarddistance = new System.Windows.Forms.TextBox();
this._textbox_quote_conditional_ticks = new System.Windows.Forms.TextBox();
this._textbox_quote_throttle_outsideticks = new System.Windows.Forms.TextBox();
this._textbox_quote_throttle_insideticks = new System.Windows.Forms.TextBox();
this._textbox_quote_showqty_qty = new System.Windows.Forms.TextBox();
this.label11 = new System.Windows.Forms.Label();
this._checkbox_quote_insidemarketdistance = new System.Windows.Forms.CheckBox();
this.label10 = new System.Windows.Forms.Label();
this._checkbox_quote_conditional = new System.Windows.Forms.CheckBox();
this.label9 = new System.Windows.Forms.Label();
this.label8 = new System.Windows.Forms.Label();
this._checkbox_quote_throttle = new System.Windows.Forms.CheckBox();
this.label7 = new System.Windows.Forms.Label();
this._checkbox_quote_showqty = new System.Windows.Forms.CheckBox();
this.label6 = new System.Windows.Forms.Label();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this._textbox_prehedge_payless_paylessticks = new System.Windows.Forms.TextBox();
this._textbox_prehedge_payup_payupticks = new System.Windows.Forms.TextBox();
this._textbox_prehedge_payup_threshold = new System.Windows.Forms.TextBox();
this._textbox_prehedge_payless_threshold = new System.Windows.Forms.TextBox();
this.label13 = new System.Windows.Forms.Label();
this.label14 = new System.Windows.Forms.Label();
this.label15 = new System.Windows.Forms.Label();
this._checkbox_prehedge_payup = new System.Windows.Forms.CheckBox();
this.label16 = new System.Windows.Forms.Label();
this._checkbox_prehedge_payless = new System.Windows.Forms.CheckBox();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this._textbox_posthedge_sizebasedcross_crossticks = new System.Windows.Forms.TextBox();
this._textbox_posthedge_sizebasedcross_threshold = new System.Windows.Forms.TextBox();
this._textbox_posthedge_timesbasedcross_crossticks = new System.Windows.Forms.TextBox();
this._textbox_posthedge_timesbasedcross_timems = new System.Windows.Forms.TextBox();
this._textbox_posthedge_ticksawaycross_crossticks = new System.Windows.Forms.TextBox();
this._textbox_posthedge_ticksawaycross_threshold = new System.Windows.Forms.TextBox();
this.label20 = new System.Windows.Forms.Label();
this.label21 = new System.Windows.Forms.Label();
this._checkbox_posthedge_sizebasedcross = new System.Windows.Forms.CheckBox();
this.label12 = new System.Windows.Forms.Label();
this.label17 = new System.Windows.Forms.Label();
this.label18 = new System.Windows.Forms.Label();
this._checkbox_posthedge_timebasedcross = new System.Windows.Forms.CheckBox();
this.label19 = new System.Windows.Forms.Label();
this._checkbox_posthedge_ticksawaycross = new System.Windows.Forms.CheckBox();
this._textbox_leg_qty = new System.Windows.Forms.TextBox();
this._checkbox_leg_enablequoting = new System.Windows.Forms.CheckBox();
this._textbox_leg_leanqtyfactor = new System.Windows.Forms.TextBox();
this._combobox_mdtype = new System.Windows.Forms.ComboBox();
this._textbox_leg_price_mult = new System.Windows.Forms.TextBox();
this.label4 = new System.Windows.Forms.Label();
this._label_leanqty_factor = new System.Windows.Forms.Label();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.groupBox3.SuspendLayout();
this.SuspendLayout();
//
// _combobox_security
//
this._combobox_security.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this._combobox_security.FormattingEnabled = true;
this._combobox_security.Location = new System.Drawing.Point(157, 15);
this._combobox_security.Name = "_combobox_security";
this._combobox_security.Size = new System.Drawing.Size(100, 23);
this._combobox_security.TabIndex = 0;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(16, 23);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(49, 15);
this.label1.TabIndex = 1;
this.label1.Text = "Security";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(16, 58);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(53, 15);
this.label2.TabIndex = 2;
this.label2.Text = "Quantity";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(16, 128);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(89, 15);
this.label3.TabIndex = 3;
this.label3.Text = "Enable Quoting";
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(16, 198);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(98, 15);
this.label5.TabIndex = 5;
this.label5.Text = "Market Data Type";
//
// groupBox1
//
this.groupBox1.Controls.Add(this._textbox_quote_qho_length);
this.groupBox1.Controls.Add(this._textbox_quote_insidemarketdistance_towarddistance);
this.groupBox1.Controls.Add(this._textbox_quote_conditional_ticks);
this.groupBox1.Controls.Add(this._textbox_quote_throttle_outsideticks);
this.groupBox1.Controls.Add(this._textbox_quote_throttle_insideticks);
this.groupBox1.Controls.Add(this._textbox_quote_showqty_qty);
this.groupBox1.Controls.Add(this.label11);
this.groupBox1.Controls.Add(this._checkbox_quote_insidemarketdistance);
this.groupBox1.Controls.Add(this.label10);
this.groupBox1.Controls.Add(this._checkbox_quote_conditional);
this.groupBox1.Controls.Add(this.label9);
this.groupBox1.Controls.Add(this.label8);
this.groupBox1.Controls.Add(this._checkbox_quote_throttle);
this.groupBox1.Controls.Add(this.label7);
this.groupBox1.Controls.Add(this._checkbox_quote_showqty);
this.groupBox1.Controls.Add(this.label6);
this.groupBox1.ForeColor = System.Drawing.Color.Black;
this.groupBox1.Location = new System.Drawing.Point(12, 238);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(265, 369);
this.groupBox1.TabIndex = 6;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Quote";
//
// _textbox_quote_qho_length
//
this._textbox_quote_qho_length.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_quote_qho_length.Location = new System.Drawing.Point(145, 28);
this._textbox_quote_qho_length.Name = "_textbox_quote_qho_length";
this._textbox_quote_qho_length.Size = new System.Drawing.Size(100, 23);
this._textbox_quote_qho_length.TabIndex = 6;
//
// _textbox_quote_insidemarketdistance_towarddistance
//
this._textbox_quote_insidemarketdistance_towarddistance.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_quote_insidemarketdistance_towarddistance.Location = new System.Drawing.Point(145, 314);
this._textbox_quote_insidemarketdistance_towarddistance.Name = "_textbox_quote_insidemarketdistance_towarddistance";
this._textbox_quote_insidemarketdistance_towarddistance.Size = new System.Drawing.Size(100, 23);
this._textbox_quote_insidemarketdistance_towarddistance.TabIndex = 15;
//
// _textbox_quote_conditional_ticks
//
this._textbox_quote_conditional_ticks.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_quote_conditional_ticks.Location = new System.Drawing.Point(145, 250);
this._textbox_quote_conditional_ticks.Name = "_textbox_quote_conditional_ticks";
this._textbox_quote_conditional_ticks.Size = new System.Drawing.Size(100, 23);
this._textbox_quote_conditional_ticks.TabIndex = 13;
//
// _textbox_quote_throttle_outsideticks
//
this._textbox_quote_throttle_outsideticks.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_quote_throttle_outsideticks.Location = new System.Drawing.Point(145, 186);
this._textbox_quote_throttle_outsideticks.Name = "_textbox_quote_throttle_outsideticks";
this._textbox_quote_throttle_outsideticks.Size = new System.Drawing.Size(100, 23);
this._textbox_quote_throttle_outsideticks.TabIndex = 11;
//
// _textbox_quote_throttle_insideticks
//
this._textbox_quote_throttle_insideticks.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_quote_throttle_insideticks.Location = new System.Drawing.Point(145, 156);
this._textbox_quote_throttle_insideticks.Name = "_textbox_quote_throttle_insideticks";
this._textbox_quote_throttle_insideticks.Size = new System.Drawing.Size(100, 23);
this._textbox_quote_throttle_insideticks.TabIndex = 10;
//
// _textbox_quote_showqty_qty
//
this._textbox_quote_showqty_qty.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_quote_showqty_qty.Location = new System.Drawing.Point(145, 92);
this._textbox_quote_showqty_qty.Name = "_textbox_quote_showqty_qty";
this._textbox_quote_showqty_qty.Size = new System.Drawing.Size(100, 23);
this._textbox_quote_showqty_qty.TabIndex = 8;
//
// label11
//
this.label11.AutoSize = true;
this.label11.Location = new System.Drawing.Point(45, 322);
this.label11.Name = "label11";
this.label11.Size = new System.Drawing.Size(93, 15);
this.label11.TabIndex = 16;
this.label11.Text = "Toward Distance";
//
// _checkbox_quote_insidemarketdistance
//
this._checkbox_quote_insidemarketdistance.AutoSize = true;
this._checkbox_quote_insidemarketdistance.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_quote_insidemarketdistance.Location = new System.Drawing.Point(15, 288);
this._checkbox_quote_insidemarketdistance.Name = "_checkbox_quote_insidemarketdistance";
this._checkbox_quote_insidemarketdistance.Size = new System.Drawing.Size(131, 19);
this._checkbox_quote_insidemarketdistance.TabIndex = 14;
this._checkbox_quote_insidemarketdistance.Text = "Inside Market Dist.";
this._checkbox_quote_insidemarketdistance.UseVisualStyleBackColor = true;
this._checkbox_quote_insidemarketdistance.CheckedChanged += new System.EventHandler(this._checkbox_quote_insidemarketdistance_CheckedChanged);
//
// label10
//
this.label10.AutoSize = true;
this.label10.Location = new System.Drawing.Point(47, 258);
this.label10.Name = "label10";
this.label10.Size = new System.Drawing.Size(33, 15);
this.label10.TabIndex = 14;
this.label10.Text = "Ticks";
//
// _checkbox_quote_conditional
//
this._checkbox_quote_conditional.AutoSize = true;
this._checkbox_quote_conditional.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_quote_conditional.Location = new System.Drawing.Point(15, 224);
this._checkbox_quote_conditional.Name = "_checkbox_quote_conditional";
this._checkbox_quote_conditional.Size = new System.Drawing.Size(88, 19);
this._checkbox_quote_conditional.TabIndex = 12;
this._checkbox_quote_conditional.Text = "Conditional";
this._checkbox_quote_conditional.UseVisualStyleBackColor = true;
this._checkbox_quote_conditional.CheckedChanged += new System.EventHandler(this._checkbox_quote_conditional_CheckedChanged);
//
// label9
//
this.label9.AutoSize = true;
this.label9.Location = new System.Drawing.Point(45, 194);
this.label9.Name = "label9";
this.label9.Size = new System.Drawing.Size(77, 15);
this.label9.TabIndex = 12;
this.label9.Text = "Outside Ticks";
//
// label8
//
this.label8.AutoSize = true;
this.label8.Location = new System.Drawing.Point(45, 164);
this.label8.Name = "label8";
this.label8.Size = new System.Drawing.Size(67, 15);
this.label8.TabIndex = 11;
this.label8.Text = "Inside Ticks";
//
// _checkbox_quote_throttle
//
this._checkbox_quote_throttle.AutoSize = true;
this._checkbox_quote_throttle.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_quote_throttle.Location = new System.Drawing.Point(15, 130);
this._checkbox_quote_throttle.Name = "_checkbox_quote_throttle";
this._checkbox_quote_throttle.Size = new System.Drawing.Size(72, 19);
this._checkbox_quote_throttle.TabIndex = 9;
this._checkbox_quote_throttle.Text = "Throttle";
this._checkbox_quote_throttle.UseVisualStyleBackColor = true;
this._checkbox_quote_throttle.CheckedChanged += new System.EventHandler(this._checkbox_quote_throttle_CheckedChanged);
//
// label7
//
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(45, 100);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(53, 15);
this.label7.TabIndex = 9;
this.label7.Text = "Quantity";
//
// _checkbox_quote_showqty
//
this._checkbox_quote_showqty.AutoSize = true;
this._checkbox_quote_showqty.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_quote_showqty.Location = new System.Drawing.Point(15, 66);
this._checkbox_quote_showqty.Name = "_checkbox_quote_showqty";
this._checkbox_quote_showqty.Size = new System.Drawing.Size(108, 19);
this._checkbox_quote_showqty.TabIndex = 7;
this._checkbox_quote_showqty.Text = "Show Quantity";
this._checkbox_quote_showqty.UseVisualStyleBackColor = true;
this._checkbox_quote_showqty.CheckedChanged += new System.EventHandler(this._checkbox_quote_showqty_CheckedChanged);
//
// label6
//
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(15, 36);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(121, 15);
this.label6.TabIndex = 6;
this.label6.Text = "Queue Holder Length";
//
// groupBox2
//
this.groupBox2.Controls.Add(this._textbox_prehedge_payless_paylessticks);
this.groupBox2.Controls.Add(this._textbox_prehedge_payup_payupticks);
this.groupBox2.Controls.Add(this._textbox_prehedge_payup_threshold);
this.groupBox2.Controls.Add(this._textbox_prehedge_payless_threshold);
this.groupBox2.Controls.Add(this.label13);
this.groupBox2.Controls.Add(this.label14);
this.groupBox2.Controls.Add(this.label15);
this.groupBox2.Controls.Add(this._checkbox_prehedge_payup);
this.groupBox2.Controls.Add(this.label16);
this.groupBox2.Controls.Add(this._checkbox_prehedge_payless);
this.groupBox2.Location = new System.Drawing.Point(13, 626);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(264, 234);
this.groupBox2.TabIndex = 7;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Pre-Hedge";
//
// _textbox_prehedge_payless_paylessticks
//
this._textbox_prehedge_payless_paylessticks.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_prehedge_payless_paylessticks.Location = new System.Drawing.Point(144, 90);
this._textbox_prehedge_payless_paylessticks.Name = "_textbox_prehedge_payless_paylessticks";
this._textbox_prehedge_payless_paylessticks.Size = new System.Drawing.Size(100, 23);
this._textbox_prehedge_payless_paylessticks.TabIndex = 18;
//
// _textbox_prehedge_payup_payupticks
//
this._textbox_prehedge_payup_payupticks.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_prehedge_payup_payupticks.Location = new System.Drawing.Point(144, 187);
this._textbox_prehedge_payup_payupticks.Name = "_textbox_prehedge_payup_payupticks";
this._textbox_prehedge_payup_payupticks.Size = new System.Drawing.Size(100, 23);
this._textbox_prehedge_payup_payupticks.TabIndex = 21;
//
// _textbox_prehedge_payup_threshold
//
this._textbox_prehedge_payup_threshold.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_prehedge_payup_threshold.Location = new System.Drawing.Point(144, 156);
this._textbox_prehedge_payup_threshold.Name = "_textbox_prehedge_payup_threshold";
this._textbox_prehedge_payup_threshold.Size = new System.Drawing.Size(100, 23);
this._textbox_prehedge_payup_threshold.TabIndex = 20;
//
// _textbox_prehedge_payless_threshold
//
this._textbox_prehedge_payless_threshold.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_prehedge_payless_threshold.Location = new System.Drawing.Point(144, 59);
this._textbox_prehedge_payless_threshold.Name = "_textbox_prehedge_payless_threshold";
this._textbox_prehedge_payless_threshold.Size = new System.Drawing.Size(100, 23);
this._textbox_prehedge_payless_threshold.TabIndex = 17;
//
// label13
//
this.label13.AutoSize = true;
this.label13.Location = new System.Drawing.Point(44, 98);
this.label13.Name = "label13";
this.label13.Size = new System.Drawing.Size(74, 15);
this.label13.TabIndex = 14;
this.label13.Text = "Payless Ticks";
//
// label14
//
this.label14.AutoSize = true;
this.label14.Location = new System.Drawing.Point(44, 195);
this.label14.Name = "label14";
this.label14.Size = new System.Drawing.Size(69, 15);
this.label14.TabIndex = 12;
this.label14.Text = "Payup Ticks";
//
// label15
//
this.label15.AutoSize = true;
this.label15.Location = new System.Drawing.Point(44, 164);
this.label15.Name = "label15";
this.label15.Size = new System.Drawing.Size(59, 15);
this.label15.TabIndex = 11;
this.label15.Text = "Threshold";
//
// _checkbox_prehedge_payup
//
this._checkbox_prehedge_payup.AutoSize = true;
this._checkbox_prehedge_payup.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_prehedge_payup.Location = new System.Drawing.Point(15, 129);
this._checkbox_prehedge_payup.Name = "_checkbox_prehedge_payup";
this._checkbox_prehedge_payup.Size = new System.Drawing.Size(64, 19);
this._checkbox_prehedge_payup.TabIndex = 19;
this._checkbox_prehedge_payup.Text = "Pay Up";
this._checkbox_prehedge_payup.UseVisualStyleBackColor = true;
this._checkbox_prehedge_payup.CheckedChanged += new System.EventHandler(this._checkbox_prehedge_payup_CheckedChanged);
//
// label16
//
this.label16.AutoSize = true;
this.label16.Location = new System.Drawing.Point(44, 67);
this.label16.Name = "label16";
this.label16.Size = new System.Drawing.Size(59, 15);
this.label16.TabIndex = 9;
this.label16.Text = "Threshold";
//
// _checkbox_prehedge_payless
//
this._checkbox_prehedge_payless.AutoSize = true;
this._checkbox_prehedge_payless.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_prehedge_payless.Location = new System.Drawing.Point(15, 32);
this._checkbox_prehedge_payless.Name = "_checkbox_prehedge_payless";
this._checkbox_prehedge_payless.Size = new System.Drawing.Size(71, 19);
this._checkbox_prehedge_payless.TabIndex = 16;
this._checkbox_prehedge_payless.Text = "Pay Less";
this._checkbox_prehedge_payless.UseVisualStyleBackColor = true;
this._checkbox_prehedge_payless.CheckedChanged += new System.EventHandler(this._checkbox_prehedge_payless_CheckedChanged);
//
// groupBox3
//
this.groupBox3.Controls.Add(this._textbox_posthedge_sizebasedcross_crossticks);
this.groupBox3.Controls.Add(this._textbox_posthedge_sizebasedcross_threshold);
this.groupBox3.Controls.Add(this._textbox_posthedge_timesbasedcross_crossticks);
this.groupBox3.Controls.Add(this._textbox_posthedge_timesbasedcross_timems);
this.groupBox3.Controls.Add(this._textbox_posthedge_ticksawaycross_crossticks);
this.groupBox3.Controls.Add(this._textbox_posthedge_ticksawaycross_threshold);
this.groupBox3.Controls.Add(this.label20);
this.groupBox3.Controls.Add(this.label21);
this.groupBox3.Controls.Add(this._checkbox_posthedge_sizebasedcross);
this.groupBox3.Controls.Add(this.label12);
this.groupBox3.Controls.Add(this.label17);
this.groupBox3.Controls.Add(this.label18);
this.groupBox3.Controls.Add(this._checkbox_posthedge_timebasedcross);
this.groupBox3.Controls.Add(this.label19);
this.groupBox3.Controls.Add(this._checkbox_posthedge_ticksawaycross);
this.groupBox3.Location = new System.Drawing.Point(13, 882);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Size = new System.Drawing.Size(264, 319);
this.groupBox3.TabIndex = 8;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "Post-Hedge";
//
// _textbox_posthedge_sizebasedcross_crossticks
//
this._textbox_posthedge_sizebasedcross_crossticks.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_posthedge_sizebasedcross_crossticks.Location = new System.Drawing.Point(144, 276);
this._textbox_posthedge_sizebasedcross_crossticks.Name = "_textbox_posthedge_sizebasedcross_crossticks";
this._textbox_posthedge_sizebasedcross_crossticks.Size = new System.Drawing.Size(100, 23);
this._textbox_posthedge_sizebasedcross_crossticks.TabIndex = 30;
//
// _textbox_posthedge_sizebasedcross_threshold
//
this._textbox_posthedge_sizebasedcross_threshold.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_posthedge_sizebasedcross_threshold.Location = new System.Drawing.Point(144, 246);
this._textbox_posthedge_sizebasedcross_threshold.Name = "_textbox_posthedge_sizebasedcross_threshold";
this._textbox_posthedge_sizebasedcross_threshold.Size = new System.Drawing.Size(100, 23);
this._textbox_posthedge_sizebasedcross_threshold.TabIndex = 29;
//
// _textbox_posthedge_timesbasedcross_crossticks
//
this._textbox_posthedge_timesbasedcross_crossticks.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_posthedge_timesbasedcross_crossticks.Location = new System.Drawing.Point(144, 182);
this._textbox_posthedge_timesbasedcross_crossticks.Name = "_textbox_posthedge_timesbasedcross_crossticks";
this._textbox_posthedge_timesbasedcross_crossticks.Size = new System.Drawing.Size(100, 23);
this._textbox_posthedge_timesbasedcross_crossticks.TabIndex = 27;
//
// _textbox_posthedge_timesbasedcross_timems
//
this._textbox_posthedge_timesbasedcross_timems.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_posthedge_timesbasedcross_timems.Location = new System.Drawing.Point(144, 152);
this._textbox_posthedge_timesbasedcross_timems.Name = "_textbox_posthedge_timesbasedcross_timems";
this._textbox_posthedge_timesbasedcross_timems.Size = new System.Drawing.Size(100, 23);
this._textbox_posthedge_timesbasedcross_timems.TabIndex = 26;
//
// _textbox_posthedge_ticksawaycross_crossticks
//
this._textbox_posthedge_ticksawaycross_crossticks.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_posthedge_ticksawaycross_crossticks.Location = new System.Drawing.Point(144, 88);
this._textbox_posthedge_ticksawaycross_crossticks.Name = "_textbox_posthedge_ticksawaycross_crossticks";
this._textbox_posthedge_ticksawaycross_crossticks.Size = new System.Drawing.Size(100, 23);
this._textbox_posthedge_ticksawaycross_crossticks.TabIndex = 24;
//
// _textbox_posthedge_ticksawaycross_threshold
//
this._textbox_posthedge_ticksawaycross_threshold.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_posthedge_ticksawaycross_threshold.Location = new System.Drawing.Point(144, 58);
this._textbox_posthedge_ticksawaycross_threshold.Name = "_textbox_posthedge_ticksawaycross_threshold";
this._textbox_posthedge_ticksawaycross_threshold.Size = new System.Drawing.Size(100, 23);
this._textbox_posthedge_ticksawaycross_threshold.TabIndex = 23;
//
// label20
//
this.label20.AutoSize = true;
this.label20.Location = new System.Drawing.Point(44, 284);
this.label20.Name = "label20";
this.label20.Size = new System.Drawing.Size(65, 15);
this.label20.TabIndex = 17;
this.label20.Text = "Cross Ticks";
//
// label21
//
this.label21.AutoSize = true;
this.label21.Location = new System.Drawing.Point(44, 254);
this.label21.Name = "label21";
this.label21.Size = new System.Drawing.Size(59, 15);
this.label21.TabIndex = 16;
this.label21.Text = "Threshold";
//
// _checkbox_posthedge_sizebasedcross
//
this._checkbox_posthedge_sizebasedcross.AutoSize = true;
this._checkbox_posthedge_sizebasedcross.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_posthedge_sizebasedcross.Location = new System.Drawing.Point(15, 220);
this._checkbox_posthedge_sizebasedcross.Name = "_checkbox_posthedge_sizebasedcross";
this._checkbox_posthedge_sizebasedcross.Size = new System.Drawing.Size(117, 19);
this._checkbox_posthedge_sizebasedcross.TabIndex = 28;
this._checkbox_posthedge_sizebasedcross.Text = "Size Based Cross";
this._checkbox_posthedge_sizebasedcross.UseVisualStyleBackColor = true;
this._checkbox_posthedge_sizebasedcross.CheckedChanged += new System.EventHandler(this._checkbox_posthedge_sizebasedcross_CheckedChanged);
//
// label12
//
this.label12.AutoSize = true;
this.label12.Location = new System.Drawing.Point(44, 96);
this.label12.Name = "label12";
this.label12.Size = new System.Drawing.Size(65, 15);
this.label12.TabIndex = 14;
this.label12.Text = "Cross Ticks";
//
// label17
//
this.label17.AutoSize = true;
this.label17.Location = new System.Drawing.Point(44, 190);
this.label17.Name = "label17";
this.label17.Size = new System.Drawing.Size(65, 15);
this.label17.TabIndex = 12;
this.label17.Text = "Cross Ticks";
//
// label18
//
this.label18.AutoSize = true;
this.label18.Location = new System.Drawing.Point(44, 160);
this.label18.Name = "label18";
this.label18.Size = new System.Drawing.Size(57, 15);
this.label18.TabIndex = 11;
this.label18.Text = "Time(ms)";
//
// _checkbox_posthedge_timebasedcross
//
this._checkbox_posthedge_timebasedcross.AutoSize = true;
this._checkbox_posthedge_timebasedcross.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_posthedge_timebasedcross.Location = new System.Drawing.Point(15, 126);
this._checkbox_posthedge_timebasedcross.Name = "_checkbox_posthedge_timebasedcross";
this._checkbox_posthedge_timebasedcross.Size = new System.Drawing.Size(122, 19);
this._checkbox_posthedge_timebasedcross.TabIndex = 25;
this._checkbox_posthedge_timebasedcross.Text = "Time Based Cross";
this._checkbox_posthedge_timebasedcross.UseVisualStyleBackColor = true;
this._checkbox_posthedge_timebasedcross.CheckedChanged += new System.EventHandler(this._checkbox_posthedge_timebasedcross_CheckedChanged);
//
// label19
//
this.label19.AutoSize = true;
this.label19.Location = new System.Drawing.Point(44, 66);
this.label19.Name = "label19";
this.label19.Size = new System.Drawing.Size(59, 15);
this.label19.TabIndex = 9;
this.label19.Text = "Threshold";
//
// _checkbox_posthedge_ticksawaycross
//
this._checkbox_posthedge_ticksawaycross.AutoSize = true;
this._checkbox_posthedge_ticksawaycross.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_posthedge_ticksawaycross.Location = new System.Drawing.Point(15, 32);
this._checkbox_posthedge_ticksawaycross.Name = "_checkbox_posthedge_ticksawaycross";
this._checkbox_posthedge_ticksawaycross.Size = new System.Drawing.Size(119, 19);
this._checkbox_posthedge_ticksawaycross.TabIndex = 22;
this._checkbox_posthedge_ticksawaycross.Text = "Ticks Away Cross";
this._checkbox_posthedge_ticksawaycross.UseVisualStyleBackColor = true;
this._checkbox_posthedge_ticksawaycross.CheckedChanged += new System.EventHandler(this._checkbox_posthedge_ticksawaycross_CheckedChanged);
//
// _textbox_leg_qty
//
this._textbox_leg_qty.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_leg_qty.Location = new System.Drawing.Point(157, 50);
this._textbox_leg_qty.Name = "_textbox_leg_qty";
this._textbox_leg_qty.Size = new System.Drawing.Size(100, 23);
this._textbox_leg_qty.TabIndex = 1;
this._textbox_leg_qty.Tag = "Double";
//
// _checkbox_leg_enablequoting
//
this._checkbox_leg_enablequoting.AutoSize = true;
this._checkbox_leg_enablequoting.Location = new System.Drawing.Point(157, 129);
this._checkbox_leg_enablequoting.Name = "_checkbox_leg_enablequoting";
this._checkbox_leg_enablequoting.Size = new System.Drawing.Size(15, 14);
this._checkbox_leg_enablequoting.TabIndex = 3;
this._checkbox_leg_enablequoting.UseVisualStyleBackColor = true;
//
// _textbox_leg_leanqtyfactor
//
this._textbox_leg_leanqtyfactor.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_leg_leanqtyfactor.Location = new System.Drawing.Point(157, 155);
this._textbox_leg_leanqtyfactor.Name = "_textbox_leg_leanqtyfactor";
this._textbox_leg_leanqtyfactor.Size = new System.Drawing.Size(100, 23);
this._textbox_leg_leanqtyfactor.TabIndex = 4;
//
// _combobox_mdtype
//
this._combobox_mdtype.AutoCompleteCustomSource.AddRange(new string[] {
"Merged",
"Direct"});
this._combobox_mdtype.FormattingEnabled = true;
this._combobox_mdtype.Location = new System.Drawing.Point(157, 190);
this._combobox_mdtype.Name = "_combobox_mdtype";
this._combobox_mdtype.Size = new System.Drawing.Size(100, 23);
this._combobox_mdtype.TabIndex = 5;
//
// _textbox_leg_price_mult
//
this._textbox_leg_price_mult.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_leg_price_mult.Location = new System.Drawing.Point(157, 85);
this._textbox_leg_price_mult.Name = "_textbox_leg_price_mult";
this._textbox_leg_price_mult.Size = new System.Drawing.Size(100, 23);
this._textbox_leg_price_mult.TabIndex = 2;
this._textbox_leg_price_mult.Tag = "Double";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(16, 93);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(87, 15);
this.label4.TabIndex = 10;
this.label4.Text = "Price Multiplier";
//
// _label_leanqty_factor
//
this._label_leanqty_factor.AutoSize = true;
this._label_leanqty_factor.Location = new System.Drawing.Point(16, 163);
this._label_leanqty_factor.Name = "_label_leanqty_factor";
this._label_leanqty_factor.Size = new System.Drawing.Size(90, 15);
this._label_leanqty_factor.TabIndex = 4;
this._label_leanqty_factor.Text = "Lean Qty Factor";
//
// LegControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.White;
this.Controls.Add(this._textbox_leg_price_mult);
this.Controls.Add(this.label4);
this.Controls.Add(this._combobox_mdtype);
this.Controls.Add(this._textbox_leg_leanqtyfactor);
this.Controls.Add(this._checkbox_leg_enablequoting);
this.Controls.Add(this._textbox_leg_qty);
this.Controls.Add(this.groupBox3);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.label5);
this.Controls.Add(this._label_leanqty_factor);
this.Controls.Add(this.label3);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this._combobox_security);
this.Name = "LegControl";
this.Size = new System.Drawing.Size(291, 1220);
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.groupBox3.ResumeLayout(false);
this.groupBox3.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private ComboBox _combobox_security;
private Label label1;
private Label label2;
private Label label3;
private Label label5;
private GroupBox groupBox1;
private Label label6;
private Label label11;
private CheckBox _checkbox_quote_insidemarketdistance;
private Label label10;
private CheckBox _checkbox_quote_conditional;
private Label label9;
private Label label8;
private CheckBox _checkbox_quote_throttle;
private Label label7;
private CheckBox _checkbox_quote_showqty;
private GroupBox groupBox2;
private Label label13;
private Label label14;
private Label label15;
private CheckBox _checkbox_prehedge_payup;
private Label label16;
private CheckBox _checkbox_prehedge_payless;
private GroupBox groupBox3;
private Label label20;
private Label label21;
private CheckBox _checkbox_posthedge_sizebasedcross;
private Label label12;
private Label label17;
private Label label18;
private CheckBox _checkbox_posthedge_timebasedcross;
private Label label19;
private CheckBox _checkbox_posthedge_ticksawaycross;
private TextBox _textbox_leg_qty;
private CheckBox _checkbox_leg_enablequoting;
private TextBox _textbox_leg_leanqtyfactor;
private ComboBox _combobox_mdtype;
private TextBox _textbox_quote_insidemarketdistance_towarddistance;
private TextBox _textbox_quote_conditional_ticks;
private TextBox _textbox_quote_throttle_outsideticks;
private TextBox _textbox_quote_throttle_insideticks;
private TextBox _textbox_quote_showqty_qty;
private TextBox _textbox_prehedge_payless_paylessticks;
private TextBox _textbox_prehedge_payup_payupticks;
private TextBox _textbox_prehedge_payup_threshold;
private TextBox _textbox_prehedge_payless_threshold;
private TextBox _textbox_posthedge_sizebasedcross_crossticks;
private TextBox _textbox_posthedge_sizebasedcross_threshold;
private TextBox _textbox_posthedge_timesbasedcross_crossticks;
private TextBox _textbox_posthedge_timesbasedcross_timems;
private TextBox _textbox_posthedge_ticksawaycross_crossticks;
private TextBox _textbox_posthedge_ticksawaycross_threshold;
private TextBox _textbox_quote_qho_length;
private TextBox _textbox_leg_price_mult;
private Label label4;
private Label _label_leanqty_factor;
}
}
@@ -1,305 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.Reflection;
namespace SpreaderFrontEnd {
// UI control that represents a spreader leg. This is hidden within the MainSpreaderForm
public partial class LegControl : UserControl {
private SpreaderLegContract _leg_contract = new SpreaderLegContract();
private IEnumerable<string> _securities = new List<string>();
public LegControl() {
InitializeComponent();
}
public void initialize(IEnumerable<string> securities, SpreaderLegContract? leg_contract) {
_securities = securities;
_leg_contract = leg_contract ?? new SpreaderLegContract();
_populate_ui();
}
#region Data -> UI
private void _populate_ui() {
_populate_basic();
_populate_quote();
_populate_prehedge();
_populate_posthedge();
_initialize_enablement();
_assign_events();
}
void _assign_events() {
foreach (System.Reflection.FieldInfo fi in GetType().GetFields(BindingFlags.NonPublic
| BindingFlags.Public
| BindingFlags.Instance)) {
if (fi.FieldType == typeof(TextBox)) {
object? val = fi.GetValue(this);
if (val != null) {
TextBox? textbox = val as TextBox;
if (textbox != null) {
textbox.TextChanged += Textbox_TextChanged;
textbox.EnabledChanged += Textbox_EnabledChanged;
}
}
}
}
}
private void Textbox_EnabledChanged(object? sender, EventArgs e) {
}
private void Textbox_TextChanged(object? sender, EventArgs e) {
if (sender != null && sender is TextBox) {
TextBox? tb = sender as TextBox;
if (tb == null)
return;
if ("Double".Equals(tb.Tag)) {
double res;
bool parsed = Double.TryParse(tb.Text, out res);
tb.ForeColor = parsed ? Color.Black : Color.Red;
} else {
UInt32 res;
bool parsed = UInt32.TryParse(tb.Text, out res);
tb.ForeColor = parsed ? Color.Black : Color.Red;
}
}
}
void _populate_basic() {
// security
_combobox_security.Items.Clear();
List<string> securities_plus_empty = new List<string>(_securities);
securities_plus_empty.Add(String.Empty);
_combobox_security.Items.AddRange(securities_plus_empty.ToArray());
_combobox_security.Text = _leg_contract.security;
// qty etc
_textbox_leg_qty.Text = _leg_contract.qty.ToString();
_textbox_leg_price_mult.Text = _leg_contract.price_mult.ToString();
_checkbox_leg_enablequoting.Checked = _leg_contract.enable_quoting;
_textbox_leg_leanqtyfactor.Text = _leg_contract.lean_qty_factor.ToString();
_combobox_mdtype.Text = _leg_contract.md_type.ToString();
}
void _populate_quote() {
Debug.Assert(_leg_contract.quote_params != null);
var qp = _leg_contract.quote_params;
_textbox_quote_qho_length.Text = qp.qho_length.ToString();
// show qty
_checkbox_quote_showqty.Checked = qp.show_qty != null;
if (qp.show_qty != null) {
_checkbox_quote_showqty.Checked = true;
_textbox_quote_showqty_qty.Text = qp.show_qty.show_qty.ToString();
}
// throttle
_checkbox_quote_throttle.Checked = qp.throttle != null;
if (qp.throttle != null) {
_textbox_quote_throttle_insideticks.Text = qp.throttle.inside_ticks.ToString();
_textbox_quote_throttle_outsideticks.Text = qp.throttle.outside_ticks.ToString();
}
// conditional
_checkbox_quote_conditional.Checked = qp.conditional != null;
if (qp.conditional != null) {
_textbox_quote_conditional_ticks.Text = qp.conditional.ticks.ToString();
}
// inside market dist.
_checkbox_quote_insidemarketdistance.Checked = qp.inside_market_distance != null;
if (qp.inside_market_distance != null) {
_textbox_quote_insidemarketdistance_towarddistance.Text = qp.inside_market_distance.ToString();
}
}
void _populate_prehedge() {
var ph = _leg_contract.pre_hedge_params;
// payless
_checkbox_prehedge_payless.Checked = ph.payless != null;
if (ph.payless != null) {
_textbox_prehedge_payless_threshold.Text = ph.payless.threshold.ToString();
_textbox_prehedge_payless_paylessticks.Text = ph.payless.payless_ticks.ToString();
}
// payup
_checkbox_prehedge_payup.Checked = ph.payup != null;
if (ph.payup != null) {
_textbox_prehedge_payup_threshold.Text = ph.payup.threshold.ToString();
_textbox_prehedge_payup_payupticks.Text = ph.payup.payup_ticks.ToString();
}
}
void _populate_posthedge() {
var ph = _leg_contract.post_hedge_params;
_checkbox_posthedge_ticksawaycross.Checked = ph.ticks_away_cross != null;
// ticks away cross
if (ph.ticks_away_cross != null) {
_textbox_posthedge_ticksawaycross_threshold.Text = ph.ticks_away_cross.threshold.ToString();
_textbox_posthedge_ticksawaycross_crossticks.Text = ph.ticks_away_cross.cross_ticks.ToString();
}
//time based cross
_checkbox_posthedge_timebasedcross.Checked = ph.time_based_cross != null;
if (ph.time_based_cross != null) {
_textbox_posthedge_timesbasedcross_timems.Text = ph.time_based_cross.time_ms.ToString();
_textbox_posthedge_timesbasedcross_crossticks.Text = ph.time_based_cross.cross_ticks.ToString();
}
// size based cross
_checkbox_posthedge_sizebasedcross.Checked = ph.size_based_cross != null;
if (ph.size_based_cross != null) {
_textbox_posthedge_sizebasedcross_threshold.Text = ph.size_based_cross.threshold.ToString();
_textbox_posthedge_sizebasedcross_crossticks.Text = ph.size_based_cross.ToString();
}
}
// forces checkbox events so that the text boxes connected to it are enabled/disabled
private void _initialize_enablement() {
_checkbox_quote_showqty_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
_checkbox_quote_throttle_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
_checkbox_quote_conditional_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
_checkbox_quote_insidemarketdistance_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
_checkbox_prehedge_payless_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
_checkbox_prehedge_payup_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
_checkbox_posthedge_ticksawaycross_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
_checkbox_posthedge_timebasedcross_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
_checkbox_posthedge_sizebasedcross_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
}
#endregion
#region UI -> Data
public ParsedUIData<SpreaderLegContract> get_data() {
SpreaderLegContract rv = new SpreaderLegContract();
try {
// top part
rv.security = _combobox_security.Text;
rv.qty = Int32.Parse(_textbox_leg_qty.Text);
rv.price_mult = Double.Parse(_textbox_leg_price_mult.Text);
rv.enable_quoting = _checkbox_leg_enablequoting.Checked;
rv.lean_qty_factor = Double.Parse(_textbox_leg_leanqtyfactor.Text);
rv.md_type = SpreaderLegContract.MDType.Merged;
// Quote
rv.quote_params = new SpreaderLegContract.QuoteParams();
rv.quote_params.qho_length = String.IsNullOrEmpty(_textbox_quote_qho_length.Text) ? 0 :
UInt32.Parse(_textbox_quote_qho_length.Text);
rv.quote_params.show_qty = null;
if (_checkbox_quote_showqty.Checked) {
rv.quote_params.show_qty = new SpreaderLegContract.QuoteParams.ShowQty();
rv.quote_params.show_qty.show_qty = UInt32.Parse(_textbox_quote_showqty_qty.Text);
}
rv.quote_params.throttle = null;
if (_checkbox_quote_throttle.Checked) {
rv.quote_params.throttle = new SpreaderLegContract.QuoteParams.Throttle();
rv.quote_params.throttle.inside_ticks = UInt32.Parse(_textbox_quote_throttle_insideticks.Text);
rv.quote_params.throttle.outside_ticks = UInt32.Parse(_textbox_quote_throttle_outsideticks.Text);
}
rv.quote_params.conditional = null;
if (_checkbox_quote_conditional.Checked) {
rv.quote_params.conditional = new SpreaderLegContract.QuoteParams.Conditional();
rv.quote_params.conditional.ticks = Int32.Parse(_textbox_quote_conditional_ticks.Text);
}
rv.quote_params.inside_market_distance = null;
if (_checkbox_quote_insidemarketdistance.Checked) {
rv.quote_params.inside_market_distance = new SpreaderLegContract.QuoteParams.InsideMarketDistance();
rv.quote_params.inside_market_distance.toward_distance =
UInt32.Parse(_textbox_quote_insidemarketdistance_towarddistance.Text);
}
//Pre-Hedge
rv.pre_hedge_params = new SpreaderLegContract.PreHedgeParams();
rv.pre_hedge_params.payless = null;
if (_checkbox_prehedge_payless.Checked) {
rv.pre_hedge_params.payless = new SpreaderLegContract.PreHedgeParams.PayLess();
rv.pre_hedge_params.payless.threshold = UInt32.Parse(_textbox_prehedge_payless_threshold.Text);
rv.pre_hedge_params.payless.payless_ticks =
UInt32.Parse(_textbox_prehedge_payless_paylessticks.Text);
}
rv.pre_hedge_params.payup = null;
if (_checkbox_prehedge_payup.Checked) {
rv.pre_hedge_params.payup = new SpreaderLegContract.PreHedgeParams.PayUp();
rv.pre_hedge_params.payup.threshold = UInt32.Parse(_textbox_prehedge_payup_threshold.Text);
rv.pre_hedge_params.payup.payup_ticks = UInt32.Parse(_textbox_prehedge_payup_payupticks.Text);
}
//Post-Hedge
rv.post_hedge_params = new SpreaderLegContract.PostHedgeParams();
rv.post_hedge_params.ticks_away_cross = null;
if (_checkbox_posthedge_ticksawaycross.Checked) {
rv.post_hedge_params.ticks_away_cross = new SpreaderLegContract.PostHedgeParams.TicksAwayCross();
rv.post_hedge_params.ticks_away_cross.threshold = UInt32.Parse(_textbox_posthedge_ticksawaycross_threshold.Text);
rv.post_hedge_params.ticks_away_cross.cross_ticks = UInt32.Parse(_textbox_posthedge_ticksawaycross_crossticks.Text);
}
rv.post_hedge_params.time_based_cross = null;
if (_checkbox_posthedge_timebasedcross.Checked) {
rv.post_hedge_params.time_based_cross = new SpreaderLegContract.PostHedgeParams.TimeBasedCross();
rv.post_hedge_params.time_based_cross.time_ms =
UInt32.Parse(_textbox_posthedge_timesbasedcross_timems.Text);
rv.post_hedge_params.time_based_cross.cross_ticks =
UInt32.Parse(_textbox_posthedge_timesbasedcross_crossticks.Text);
}
rv.post_hedge_params.size_based_cross = null;
if (_checkbox_posthedge_sizebasedcross.Checked) {
rv.post_hedge_params.size_based_cross = new SpreaderLegContract.PostHedgeParams.SizedBasedCross();
rv.post_hedge_params.size_based_cross.threshold = UInt32.Parse(_textbox_posthedge_sizebasedcross_threshold.Text);
rv.post_hedge_params.size_based_cross.cross_ticks = UInt32.Parse(_textbox_posthedge_sizebasedcross_crossticks.Text);
}
}
catch(Exception ex) {
return new ParsedUIData<SpreaderLegContract>(null, true, ex.Message);
}
return new ParsedUIData<SpreaderLegContract>(rv, false, String.Empty);
}
#endregion
public SpreaderLegContract get_contract() {
return null;
}
#region Checkbox Check Change Events
private void _checkbox_quote_showqty_CheckedChanged(object sender, EventArgs e) {
_textbox_quote_showqty_qty.Enabled = _checkbox_quote_showqty.Checked;
}
private void _checkbox_quote_throttle_CheckedChanged(object sender, EventArgs e) {
_textbox_quote_throttle_insideticks.Enabled = _checkbox_quote_throttle.Checked;
_textbox_quote_throttle_outsideticks.Enabled = _checkbox_quote_throttle.Checked;
}
private void _checkbox_quote_conditional_CheckedChanged(object sender, EventArgs e) {
_textbox_quote_conditional_ticks.Enabled = _checkbox_quote_conditional.Checked;
}
private void _checkbox_quote_insidemarketdistance_CheckedChanged(object sender, EventArgs e) {
_textbox_quote_insidemarketdistance_towarddistance.Enabled = _checkbox_quote_insidemarketdistance.Checked;
}
private void _checkbox_prehedge_payless_CheckedChanged(object sender, EventArgs e) {
_textbox_prehedge_payless_threshold.Enabled = _checkbox_prehedge_payless.Checked;
_textbox_prehedge_payless_paylessticks.Enabled = _checkbox_prehedge_payless.Checked;
}
private void _checkbox_prehedge_payup_CheckedChanged(object sender, EventArgs e) {
_textbox_prehedge_payup_threshold.Enabled = _checkbox_prehedge_payup.Checked;
_textbox_prehedge_payup_payupticks.Enabled = _checkbox_prehedge_payup.Checked;
}
private void _checkbox_posthedge_ticksawaycross_CheckedChanged(object sender, EventArgs e) {
_textbox_posthedge_ticksawaycross_threshold.Enabled = _checkbox_posthedge_ticksawaycross.Checked;
_textbox_posthedge_ticksawaycross_crossticks.Enabled = _checkbox_posthedge_ticksawaycross.Checked;
}
private void _checkbox_posthedge_timebasedcross_CheckedChanged(object sender, EventArgs e) {
_textbox_posthedge_timesbasedcross_timems.Enabled = _checkbox_posthedge_timebasedcross.Checked;
_textbox_posthedge_timesbasedcross_crossticks.Enabled = _checkbox_posthedge_timebasedcross.Checked;
}
private void _checkbox_posthedge_sizebasedcross_CheckedChanged(object sender, EventArgs e) {
_textbox_posthedge_sizebasedcross_threshold.Enabled = _checkbox_posthedge_sizebasedcross.Checked;
_textbox_posthedge_sizebasedcross_crossticks.Enabled = _checkbox_posthedge_sizebasedcross.Checked;
}
#endregion
}
}
@@ -1,60 +0,0 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -1,152 +0,0 @@
using System.Windows.Forms;
namespace SpreaderFrontEnd
{
partial class MainSpreaderForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this._button_ok = new System.Windows.Forms.Button();
this._button_cancel = new System.Windows.Forms.Button();
this._label_spreader_name = new System.Windows.Forms.Label();
this._textbox_spreader_name = new System.Windows.Forms.TextBox();
this._legcontrol1 = new SpreaderFrontEnd.LegControl();
this._legcontrol2 = new SpreaderFrontEnd.LegControl();
this._legcontrol3 = new SpreaderFrontEnd.LegControl();
this._legcontrol4 = new SpreaderFrontEnd.LegControl();
this._legcontrol5 = new SpreaderFrontEnd.LegControl();
this.SuspendLayout();
//
// _button_ok
//
this._button_ok.Location = new System.Drawing.Point(1231, 1306);
this._button_ok.Name = "_button_ok";
this._button_ok.Size = new System.Drawing.Size(120, 33);
this._button_ok.TabIndex = 4;
this._button_ok.Text = "OK";
this._button_ok.UseVisualStyleBackColor = false;
this._button_ok.Click += new System.EventHandler(this._button_ok_Click);
//
// _button_cancel
//
this._button_cancel.Location = new System.Drawing.Point(1380, 1306);
this._button_cancel.Name = "_button_cancel";
this._button_cancel.Size = new System.Drawing.Size(121, 33);
this._button_cancel.TabIndex = 5;
this._button_cancel.Text = "Cancel";
this._button_cancel.UseVisualStyleBackColor = false;
this._button_cancel.Click += new System.EventHandler(this._button_cancel_Click);
//
// _label_spreader_name
//
this._label_spreader_name.AutoSize = true;
this._label_spreader_name.Location = new System.Drawing.Point(22, 28);
this._label_spreader_name.Name = "_label_spreader_name";
this._label_spreader_name.Size = new System.Drawing.Size(88, 15);
this._label_spreader_name.TabIndex = 6;
this._label_spreader_name.Text = "Spreader Name";
//
// _textbox_spreader_name
//
this._textbox_spreader_name.Location = new System.Drawing.Point(116, 25);
this._textbox_spreader_name.Name = "_textbox_spreader_name";
this._textbox_spreader_name.Size = new System.Drawing.Size(343, 23);
this._textbox_spreader_name.TabIndex = 0;
//
// _legcontrol1
//
this._legcontrol1.BackColor = System.Drawing.Color.White;
this._legcontrol1.Location = new System.Drawing.Point(22, 67);
this._legcontrol1.Name = "_legcontrol1";
this._legcontrol1.Size = new System.Drawing.Size(291, 1220);
this._legcontrol1.TabIndex = 1;
//
// _legcontrol2
//
this._legcontrol2.BackColor = System.Drawing.Color.White;
this._legcontrol2.Location = new System.Drawing.Point(319, 67);
this._legcontrol2.Name = "_legcontrol2";
this._legcontrol2.Size = new System.Drawing.Size(291, 1220);
this._legcontrol2.TabIndex = 2;
//
// _legcontrol3
//
this._legcontrol3.BackColor = System.Drawing.Color.White;
this._legcontrol3.Location = new System.Drawing.Point(616, 67);
this._legcontrol3.Name = "_legcontrol3";
this._legcontrol3.Size = new System.Drawing.Size(291, 1220);
this._legcontrol3.TabIndex = 3;
//
// _legcontrol4
//
this._legcontrol4.BackColor = System.Drawing.Color.White;
this._legcontrol4.Location = new System.Drawing.Point(913, 67);
this._legcontrol4.Name = "_legcontrol4";
this._legcontrol4.Size = new System.Drawing.Size(291, 1220);
this._legcontrol4.TabIndex = 4;
//
// _legcontrol5
//
this._legcontrol5.BackColor = System.Drawing.Color.White;
this._legcontrol5.Location = new System.Drawing.Point(1210, 67);
this._legcontrol5.Name = "_legcontrol5";
this._legcontrol5.Size = new System.Drawing.Size(291, 1220);
this._legcontrol5.TabIndex = 5;
//
// MainSpreaderForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1517, 1363);
this.Controls.Add(this._legcontrol5);
this.Controls.Add(this._legcontrol4);
this.Controls.Add(this._legcontrol3);
this.Controls.Add(this._legcontrol2);
this.Controls.Add(this._legcontrol1);
this.Controls.Add(this._textbox_spreader_name);
this.Controls.Add(this._label_spreader_name);
this.Controls.Add(this._button_cancel);
this.Controls.Add(this._button_ok);
this.Name = "MainSpreaderForm";
this.Text = "MainSpreaderForm";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private Button _button_ok;
private Button _button_cancel;
private Label _label_spreader_name;
private TextBox _textbox_spreader_name;
private LegControl _legcontrol1;
private LegControl _legcontrol2;
private LegControl _legcontrol3;
private LegControl _legcontrol4;
private LegControl _legcontrol5;
}
}
@@ -1,81 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SpreaderFrontEnd {
// This is the main UI widget. It is passed a list of securities and a SpreaderContract.
// The SpreaderContract can be empty (which will be the case when creating a new spreader).
// It has 3 public facing members (other than the constructor),
// 2 events that tell whether OK or Cancel was hit, respectively,
// and get_spreader_contract that returns a ParsedUIData<SpreaderContract>
public partial class MainSpreaderForm : Form {
private IEnumerable<LegControl> _leg_controls;
public Action on_OK = () => { };
public Action on_cancel = () => { };
private readonly IEnumerable<string> _securities;
private SpreaderContract _spreader_contract;
public MainSpreaderForm(IEnumerable<string> securities,
SpreaderContract spreader_contract)
: base() {
InitializeComponent();
_leg_controls = new LegControl[] { _legcontrol1, _legcontrol2, _legcontrol3, _legcontrol4, _legcontrol5 };
_securities = securities;
System.Diagnostics.Debug.Assert(spreader_contract != null);
// System.Diagnostics.Debug.Assert(spreader_contract.spread_legs.Count() == SpreaderContract.max_nlegs);
_spreader_contract = spreader_contract;
_textbox_spreader_name.Text = _spreader_contract.name;
for (var i = 0; i < _leg_controls.Count(); i++) {
SpreaderLegContract? lc = i < _spreader_contract.spread_legs.Count() ?
_spreader_contract.spread_legs.ElementAt(i) : null;
_leg_controls.ElementAt(i).initialize(securities, lc);
}
}
public ParsedUIData<SpreaderContract> get_spreader_contract() {
if (String.IsNullOrEmpty(_textbox_spreader_name.Text)) {
return new ParsedUIData<SpreaderContract>(null, true, "Spreader name is not set");
}
List<SpreaderLegContract> leg_contracts = new List<SpreaderLegContract>();
uint i = 0;
foreach (LegControl lc in _leg_controls) {
i++;
var leg_res = lc.get_data();
if (leg_res.is_error) {
return new ParsedUIData<SpreaderContract>(null, true, $"Leg: {i} is not set correctly");
}
leg_contracts.Add(leg_res.ui_data);
}
IEnumerable<SpreaderLegContract> leg_contracts_rv =
leg_contracts.Where(l => !String.IsNullOrEmpty(l.security));
if (leg_contracts_rv.Count() <= 1) {
return new ParsedUIData<SpreaderContract>(
null, true, "Spreader needs at least 2 legs");
}
// check the number of legs
return new ParsedUIData<SpreaderContract>(
new SpreaderContract(_textbox_spreader_name.Text, leg_contracts_rv), false, String.Empty);
}
private void _button_ok_Click(object sender, EventArgs e) {
ParsedUIData<SpreaderContract> ui_data = get_spreader_contract();
if (ui_data.is_error) {
string err_txt = $"The following error happened \n{ui_data.error_txt}";
System.Windows.Forms.MessageBox.Show(err_txt, "Spreader Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
on_OK();
}
private void _button_cancel_Click(object sender, EventArgs e) {
on_cancel();
}
}
}
@@ -1,60 +0,0 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -1,20 +0,0 @@
namespace SpreaderFrontEnd {
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class ParsedUIData<T> {
public readonly T ui_data;
public readonly bool is_error;
public readonly string error_txt;
public ParsedUIData(T ui_data, bool is_error, string error_txt) {
this.ui_data = ui_data;
this.is_error = is_error;
this.error_txt = error_txt;
}
}
}
@@ -1,18 +0,0 @@
using System;
using System.Windows.Forms;
namespace SpreaderFrontEnd {
internal static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
SyntheticBookTest.run();
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new TestForm());
}
}
}
@@ -1,35 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SpreaderFrontEnd
{
[Serializable]
// Represents a spreader contract (anologous ot the protobuf on the C++ side)
// We could have generated managed wrappers from the protobuf, but we did not want
// to make your build process complicated hence opted for this class.
// It is quite simply a wrapper around an enumeration of SpreaderLegContract
public class SpreaderContract
{
public static uint max_nlegs = 5;
public string name = String.Empty;
public IList<SpreaderLegContract> spread_legs = new List<SpreaderLegContract>();
public SpreaderContract(string name, IEnumerable<SpreaderLegContract> spread_legs)
{
this.name = name;
this.spread_legs = spread_legs.ToList();
}
public static SpreaderContract empty
{
get
{
return new SpreaderContract("UNNAMED",
Enumerable.Repeat<SpreaderLegContract>(new SpreaderLegContract(), 5));
}
}
}
}
@@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<LanguageVersion>7</LanguageVersion>
</PropertyGroup>
</Project>
@@ -1,90 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SpreaderFrontEnd
{
[Serializable]
// Represents a single leg of the spreader. It is made up of
// 1. a main section consisting of the security, qty, price mult etc
// 2. Quote parameters
// 3. Pre-Hedge parameters
// 4. Post-Hedge parameters
// It maps pretty directly to the UI (LegControl)
public class SpreaderLegContract
{
public enum MDType {
Direct = 0,
Merged = 1,
}
public string security = String.Empty;
public int qty = 1;
public double price_mult = 1;
public bool enable_quoting = false;
public double lean_qty_factor = 1;
public MDType md_type = MDType.Direct;
public QuoteParams quote_params = new QuoteParams();
public PreHedgeParams pre_hedge_params = new PreHedgeParams();
public PostHedgeParams post_hedge_params = new PostHedgeParams();
public class QuoteParams
{
public class ShowQty {
public UInt32 show_qty = 1;
}
public class Throttle {
public UInt32 inside_ticks = 0;
public UInt32 outside_ticks = 0;
}
public class Conditional {
public Int32 ticks = 0;
}
public class InsideMarketDistance {
public UInt32 toward_distance = 0;
}
public UInt32 qho_length = 0;
public ShowQty? show_qty = null;
public Throttle? throttle = null;
public Conditional? conditional = null;
public InsideMarketDistance? inside_market_distance = null;
}
public class PreHedgeParams
{
public class PayLess {
public UInt32 threshold = 0;
public UInt32 payless_ticks = 0;
}
public class PayUp
{
public UInt32 threshold = 0;
public UInt32 payup_ticks = 0;
}
public PayLess? payless = null;
public PayUp? payup = null;
}
public class PostHedgeParams
{
public class TicksAwayCross {
public UInt32 threshold = 0;
public UInt32 cross_ticks = 0;
}
public class TimeBasedCross {
public UInt32 time_ms = 0;
public UInt32 cross_ticks = 0;
}
public class SizedBasedCross {
public UInt32 threshold = 0;
public UInt32 cross_ticks = 0;
}
public TicksAwayCross? ticks_away_cross = null;
public TimeBasedCross? time_based_cross = null;
public SizedBasedCross? size_based_cross = null;
}
}
}
-79
View File
@@ -1,79 +0,0 @@
using System.Windows.Forms;
namespace SpreaderFrontEnd
{
partial class TestForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this._button_launch_new = new System.Windows.Forms.Button();
this._button_load_existing = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// _button_launch_new
//
this._button_launch_new.Location = new System.Drawing.Point(96, 46);
this._button_launch_new.Name = "_button_launch_new";
this._button_launch_new.Size = new System.Drawing.Size(169, 26);
this._button_launch_new.TabIndex = 0;
this._button_launch_new.Text = "Launch New";
this._button_launch_new.UseVisualStyleBackColor = true;
this._button_launch_new.Click += new System.EventHandler(this._button_launch_new_Click);
//
// _button_load_existing
//
this._button_load_existing.Location = new System.Drawing.Point(96, 114);
this._button_load_existing.Name = "_button_load_existing";
this._button_load_existing.Size = new System.Drawing.Size(169, 26);
this._button_load_existing.TabIndex = 1;
this._button_load_existing.Text = "Load Existing";
this._button_load_existing.UseVisualStyleBackColor = true;
this._button_load_existing.Click += new System.EventHandler(this._button_load_existing_Click);
//
// TestForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(371, 213);
this.Controls.Add(this._button_load_existing);
this.Controls.Add(this._button_launch_new);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "TestForm";
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.Text = "Test Launcher";
this.ResumeLayout(false);
}
#endregion
private Button _button_launch_new;
private Button _button_load_existing;
}
}
@@ -1,91 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace SpreaderFrontEnd {
// Test class that demostrates how to use the MainSpreaderForm.
// It has 2 buttons. "Launch New" launches a brand new spreader (empty UI)
// while "Launch Existing" loads the MainSpreaderForm with an existing
// spreader (hard coded arbitrary values)
public partial class TestForm : Form {
private IEnumerable<string> _securities = new string[] {
"ZCG23",
"ZCH23",
"ZCJ23",
"ZCL23",
"ZCM23"
};
public TestForm() {
InitializeComponent();
}
private void _button_launch_new_Click(object sender, EventArgs e) {
_show_form(SpreaderContract.empty);
}
private void _button_load_existing_Click(object sender, EventArgs e) {
var sc = _generate_test_contract();
_show_form(sc);
}
private void _show_form(SpreaderContract spreader_contract) {
MainSpreaderForm f = new MainSpreaderForm(_securities, spreader_contract);
f.on_OK = () => {
MessageBox.Show("Received OK", "OK", MessageBoxButtons.OK, MessageBoxIcon.Information);
f.Close();
};
f.on_cancel = () => {
MessageBox.Show("Received Cancel", "Cancel", MessageBoxButtons.OK, MessageBoxIcon.Warning);
f.Close();
};
f.ShowDialog();
}
private SpreaderContract _generate_test_contract() {
List<SpreaderLegContract> lcs = new List<SpreaderLegContract>();
for (uint i = 0; i < 3; i++) {
SpreaderLegContract lc = _generate_test_leg_contract(i);
lcs.Add(lc);
}
SpreaderContract sc = new SpreaderContract("TEST SPREADER", lcs);
return sc;
}
private SpreaderLegContract _generate_test_leg_contract(uint idx) {
SpreaderLegContract rv = new SpreaderLegContract();
rv.security = _securities.ElementAt(0);
rv.qty = 1;
rv.price_mult = 1;
rv.enable_quoting = true;
rv.lean_qty_factor = 2;
rv.md_type = SpreaderLegContract.MDType.Merged;
// quote
rv.quote_params = new SpreaderLegContract.QuoteParams();
rv.quote_params.qho_length = 0;
rv.quote_params.show_qty = new SpreaderLegContract.QuoteParams.ShowQty();
rv.quote_params.show_qty.show_qty = 10;
rv.quote_params.throttle = new SpreaderLegContract.QuoteParams.Throttle();
rv.quote_params.throttle.inside_ticks = 3;
rv.quote_params.throttle.outside_ticks = 2;
// pre hedge
rv.pre_hedge_params = new SpreaderLegContract.PreHedgeParams();
rv.pre_hedge_params.payless = new SpreaderLegContract.PreHedgeParams.PayLess();
rv.pre_hedge_params.payless.threshold = 1000;
rv.pre_hedge_params.payless.payless_ticks = 7;
rv.pre_hedge_params.payup = new SpreaderLegContract.PreHedgeParams.PayUp();
rv.pre_hedge_params.payup.threshold = 500;
rv.pre_hedge_params.payup.payup_ticks = 12;
// post hedge
rv.post_hedge_params = new SpreaderLegContract.PostHedgeParams();
rv.post_hedge_params.ticks_away_cross = new SpreaderLegContract.PostHedgeParams.TicksAwayCross();
rv.post_hedge_params.ticks_away_cross.threshold = 10;
rv.post_hedge_params.ticks_away_cross.cross_ticks = 3;
rv.post_hedge_params.time_based_cross = new SpreaderLegContract.PostHedgeParams.TimeBasedCross();
rv.post_hedge_params.time_based_cross.time_ms = 20;
rv.post_hedge_params.time_based_cross.cross_ticks = 5;
return rv;
}
}
};
@@ -1,60 +0,0 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -1,230 +0,0 @@
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
namespace SpreaderFrontEnd {
public static class SyntheticBookTest {
/// <summary>
/// Run synthetic book computation tests
/// </summary>
public static int run() {
// Seed the test with a standard butterfly spread. Leg size multipliers will be applied to
// each leg to generate more variations to test.
var legs = new List<SpreaderLegContract> {
new SpreaderLegContract() {
security = "Leg1Sec",
qty = 1
},
new SpreaderLegContract() {
security = "Leg2Sec",
qty = -2
},
new SpreaderLegContract() {
security = "Leg3Sec",
qty = 1
}
};
var leg_multipliers = new List<int> { 1, -1, 2, -2, 3, -3 };
var contract = new SpreaderContract("Test", legs);
// Define a book (seed) for each leg. Quantities will be added to each price level for each
// leg's book to generate more variations to test.
var leg1_book = new Book(
bids: new BookSide(levels: new List<PriceLevel> {
new PriceLevel(price: 3, qty: 10),
new PriceLevel(price: 2, qty: 4),
new PriceLevel(price: 1, qty: 6)
}),
asks: new BookSide(levels: new List<PriceLevel> {
new PriceLevel(price: 4, qty: 5),
new PriceLevel(price: 5, qty: 7),
new PriceLevel(price: 6, qty: 8)
}));
var leg2_book = new Book(
bids: new BookSide(levels: new List<PriceLevel> {
new PriceLevel(price: 3, qty: 1),
new PriceLevel(price: 2, qty: 7),
new PriceLevel(price: 1, qty: 2)
}),
asks: new BookSide(levels: new List<PriceLevel> {
new PriceLevel(price: 4, qty: 3),
new PriceLevel(price: 5, qty: 3),
new PriceLevel(price: 6, qty: 5)
}));
var leg3_book = new Book(
bids: new BookSide(levels: new List<PriceLevel> {
new PriceLevel(price: 3, qty: 2),
new PriceLevel(price: 2, qty: 1),
new PriceLevel(price: 1, qty: 8)
}),
asks: new BookSide(levels: new List<PriceLevel> {
new PriceLevel(price: 4, qty: 4),
new PriceLevel(price: 5, qty: 3),
new PriceLevel(price: 6, qty: 4)
}));
var level_qty_additions = new List<uint> { 1, 2, 3, 4 };
var leg_books = new List<Book> { leg1_book, leg2_book, leg3_book };
for (int i = 0; i < leg_multipliers.Count; i++) {
var leg_mult = leg_multipliers[i];
for (int j = 0; j < contract.spread_legs.Count; j++) {
// Apply leg mult
contract.spread_legs[j].qty *= leg_mult;
foreach (var lqa in level_qty_additions) {
foreach(var lb in leg_books) {
// Apply qty addition to bid-levels
for (int level_idx = 0; level_idx < lb.bids.levels.Count; level_idx++) {
var orig_level = lb.bids.levels[level_idx];
lb.bids.levels[level_idx] = orig_level.add_qty(lqa);
run(leg_books, contract);
// Subtract the qty that was just added so each qty addition is applied to
// the original level
lb.bids.levels[level_idx] = lb.bids.levels[level_idx].subtract_qty(lqa);
}
// Apply qty additions to ask-levels
for (int level_idx = 0; level_idx < lb.asks.levels.Count; level_idx++) {
var orig_level = lb.asks.levels[level_idx];
lb.asks.levels[level_idx] = orig_level.add_qty(lqa);
run(leg_books, contract);
// Subtract the qty that was just added so each qty addition is applied to
// the original level
lb.asks.levels[level_idx] = lb.asks.levels[level_idx].subtract_qty(lqa);
}
}
}
// Divide by leg_mult so the each mult is applied to the original leg
contract.spread_legs[j].qty /= leg_mult;
}
}
return 0;
}
public static void run(List<Book> leg_books, SpreaderContract contract) {
var synth_book = SpreaderBookCalculator.compute_spreader_book(contract, leg_books);
for (int i = 0; i < contract.spread_legs.Count; i++) {
Console.WriteLine($"Leg{i} (qty {contract.spread_legs[i].qty}): {leg_books[i]}");
}
Console.WriteLine($"Synthetic Book: {synth_book}");
var leg_book_tups = _to_leg_book_tuples(leg_books, contract);
var expected_book = _compute_synth_book(leg_book_tups);
Console.WriteLine($"Expected Book: {expected_book}");
Debug.Assert(expected_book.Equals(synth_book));
}
static List<Tuple<Book, int>> _to_leg_book_tuples(List<Book> leg_books, SpreaderContract contract) {
Debug.Assert(leg_books.Count == contract.spread_legs.Count);
var rv = new List<Tuple<Book, int>>();
for (int i = 0; i < leg_books.Count; i++) {
rv.Add(Tuple.Create(leg_books[i], contract.spread_legs[i].qty));
}
return rv;
}
static List<Tuple<BookSide, int>> _to_leg_book_side_tuples(List<Tuple<Book, int>> leg_books, bool is_bid) {
var leg_book_tups = new List<Tuple<BookSide, int>>();
for (int i = 0; i < leg_books.Count; i++) {
var leg_size = leg_books[i].Item2;
var leg_book = leg_books[i].Item1;
var is_buy_leg = leg_size > 0;
var leg_book_side = is_buy_leg == is_bid ? leg_book.bids : leg_book.asks;
leg_book_tups.Add(Tuple.Create(leg_book_side, leg_size));
}
return leg_book_tups;
}
static Book _compute_synth_book(List<Tuple<Book, int>> leg_books) {
var leg_bids = _to_leg_book_side_tuples(leg_books, true);
var leg_asks = _to_leg_book_side_tuples(leg_books, false);
var synth_bids = _compute_synth_book_side(leg_bids);
var synth_asks = _compute_synth_book_side(leg_asks);
return new Book(synth_bids, synth_asks);
}
// <summary>
// Computes the synthetic book in a simple/unoptimized way, to ensure correctness. Books
// generated by the 'optimized' routine, which will be used in practice, should match those
// generated by this one.
// </summary>
static BookSide _compute_synth_book_side(IEnumerable<Tuple<BookSide, int>> leg_books) {
// Clone the books so we can mutate them without changing the input 'leg_books'
var leg_books_list = leg_books.Select(lb => Tuple.Create(lb.Item1.Clone(), lb.Item2)).ToList();
var levels = new List<PriceLevel>();
var top_level = _get_top_level(leg_books_list);
while (top_level.qty > 0) {
levels.Add(top_level);
foreach (var lb in leg_books_list) {
_remove_qty_from_top(lb.Item1, (int)(top_level.qty * Math.Abs(lb.Item2)));
}
top_level = _get_top_level(leg_books_list);
}
return new BookSide(levels);
}
static PriceLevel _get_top_level(IEnumerable<Tuple<BookSide, int>> leg_books) {
var leg_sizes = leg_books.Select(lb => lb.Item2).ToList();
var top_levels = leg_books.Select(_get_top_level).ToList();
var qty = top_levels.Select(l => l.qty).Min();
if (qty == 0) {
return PriceLevel.empty;
}
double price = 0;
for (int i = 0; i < top_levels.Count; i++) {
var leg_price = top_levels[i].price;
var leg_size = leg_sizes[i];
if (leg_size < 0) {
price -= leg_price;
} else {
price += leg_price;
}
}
return new PriceLevel(price, qty);
}
static PriceLevel _get_top_level(Tuple<BookSide, int> leg_book) {
return _get_top_level(leg_book.Item1, leg_book.Item2);
}
static PriceLevel _get_top_level(BookSide book, int leg_size) {
if (book.levels.Count == 0) {
return PriceLevel.empty;
}
var first_level = book.levels.First();
var abs_leg_size = Math.Abs(leg_size);
if (first_level.qty >= abs_leg_size) {
return new PriceLevel(first_level.price * abs_leg_size, (uint)(first_level.qty / abs_leg_size));
}
double price = first_level.qty * first_level.price;
var qty_rem = abs_leg_size - first_level.qty;
for (int i = 1; i < book.levels.Count; i++) {
var level = book.levels[i];
if (level.qty >= qty_rem) {
price += qty_rem * level.price;
return new PriceLevel(price, 1);
}
price += level.qty * level.price;
qty_rem -= level.qty;
}
return PriceLevel.empty;
}
/// <summary>
/// Removes the specified quantity from the top of the book
/// </summary>
static void _remove_qty_from_top(BookSide book, int qty) {
var subtracted_qty = 0;
while (subtracted_qty < qty && book.levels.Count > 0) {
var first_level = book.levels[0];
var qty_to_subtract = qty - subtracted_qty;
if (first_level.qty > qty_to_subtract) {
first_level = first_level.subtract_qty((uint)qty_to_subtract);
book.levels[0] = first_level;
return;
}
book.levels.RemoveAt(0);
subtracted_qty += (int)first_level.qty;
}
}
}
}
@@ -1,78 +0,0 @@
using System;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
namespace SpreaderFrontEnd
{
public class Utils
{
public static void bin_serialize<T>(T t, Stream str)
{
#pragma warning disable SYSLIB0011
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(str, t);
#pragma warning restore SYSLIB0011
}
public static T bin_deserialize<T>(Stream str)
{
#pragma warning disable SYSLIB0011
BinaryFormatter bf = new BinaryFormatter();
T rv = (T)bf.Deserialize(str);
#pragma warning restore SYSLIB0011
return rv;
}
public static T? basic_deep_clone<T>(T t)
{
try
{
MemoryStream str = new MemoryStream();
bin_serialize(t, str);
str.Position = 0;
return bin_deserialize<T>(str);
}
catch
{
return default(T);
}
}
public static object? CloneObject(object objSource)
{
//step : 1 Get the type of source object and create a new instance of that type
Type typeSource = objSource.GetType();
object? objTarget = Activator.CreateInstance(typeSource);
//Step2 : Get all the properties of source object type
PropertyInfo[] propertyInfo = typeSource.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
//Step : 3 Assign all source property to taget object 's properties
foreach (PropertyInfo property in propertyInfo)
{
//Check whether property can be written to
if (property.CanWrite)
{
//Step : 4 check whether property type is value type, enum or string type
if (property.PropertyType.IsValueType || property.PropertyType.IsEnum || property.PropertyType.Equals(typeof(System.String)))
{
property.SetValue(objTarget, property.GetValue(objSource, null), null);
}
//else property type is object/complex types, so need to recursively call this method until the end of the tree is reached
else
{
object? objPropertyValue = property.GetValue(objSource, null);
if (objPropertyValue == null)
{
property.SetValue(objTarget, null, null);
}
else
{
property.SetValue(objTarget, CloneObject(objPropertyValue), null);
}
}
}
}
return objTarget;
}
}
}
@@ -1,23 +0,0 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v6.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v6.0": {
"SpreaderFrontEnd/1.0.0": {
"runtime": {
"SpreaderFrontEnd.dll": {}
}
}
}
},
"libraries": {
"SpreaderFrontEnd/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
}
}
}
@@ -1,15 +0,0 @@
{
"runtimeOptions": {
"tfm": "net6.0",
"frameworks": [
{
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
},
{
"name": "Microsoft.WindowsDesktop.App",
"version": "6.0.0"
}
]
}
}
@@ -106,8 +106,9 @@ function(Service_Compiler_Generate_Cpp SRCS HDRS)
"${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.client.pb.h"
"${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.server.pb.cc"
"${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.server.pb.h"
COMMAND
"PYTHONPATH=${SPARK_PYTHON}" ${Protobuf_PROTOC_EXECUTABLE} ARGS
COMMAND ${CMAKE_SOURCE_DIR}/tools/venv_exec.sh
ARGS
${Protobuf_PROTOC_EXECUTABLE}
--cpp_out=${CMAKE_BINARY_DIR}/src
--plugin=protoc-gen-service=${CMAKE_SOURCE_DIR}/src/lib/api/service_compiler/plugin.py
--service_out=lang=cpp,make_file_name=${ABS_FIL}:${CMAKE_BINARY_DIR}/src
File renamed without changes.
+3 -1
View File
@@ -46,6 +46,7 @@ function setup_build
assert_dir $repo_root
assert_dir $build_root
set compiler "$argv[1]"
set c_compiler (which cc)
set build_type "$argv[2]"
if test \( -z "$build_type" \) -o \( \( "$build_type" != debug \) -a \( "$build_type" != release \) \)
@@ -59,6 +60,7 @@ function setup_build
else
# set compiler_arg "/usr/lib/ccache/clang++"
set compiler_arg "clang++"
set c_compiler (which clang)
end
else if test "$build_type" = release
set build_type_arg Release
@@ -85,7 +87,7 @@ function setup_build
rm -rf "$build_dest"
mkdir -p "$build_dest"
cd "$build_dest"
cmake -G Ninja -DCMAKE_BUILD_TYPE=$build_type_arg -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_CXX_COMPILER=$compiler_arg $repo_root
cmake -G Ninja -DCMAKE_BUILD_TYPE=$build_type_arg -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_C_COMPILER=$c_compiler -DCMAKE_CXX_COMPILER=$compiler_arg $repo_root
end
# The while loop below removes arguments (via shift) as it parses them.
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"
}
}
+1
View File
@@ -12,6 +12,7 @@ pycodestyle==2.7.0
pycparser==2.20
pylint==2.10.2
PyMeta3==0.5.1
termcolor==1.1.0
toml==0.10.2
wrapt==1.12.1
yapf==0.31.0
+32 -22
View File
@@ -1,10 +1,10 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
# Visual Studio Version 17
VisualStudioVersion = 17.3.32922.545
MinimumVisualStudioVersion = 15.0.26124.0
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api", "src\client\spark_api\spark_api.csproj", "{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\libspark.vcxproj", "{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\libspark.vcxproj", "{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark", "src\client\spark\Spark.csproj", "{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}"
EndProject
@@ -12,15 +12,17 @@ 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}
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25} = {FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_test", "src\client\spark_test\spark_test.csproj", "{ECD78CC5-138F-4809-A764-2358C2AC2E82}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_websocket", "src\client\spark_websocket\spark_websocket.csproj", "{3201359D-C071-4089-9EDE-B04D759F1508}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api_server", "src\client\spark_api_server\spark_api_server.csproj", "{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -37,14 +39,14 @@ Global
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.Build.0 = Release|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.Build.0 = Release|x64
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.Debug|x64.ActiveCfg = Debug|x64
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.Debug|x64.Build.0 = Debug|x64
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.Release|x64.ActiveCfg = Release|x64
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.Release|x64.Build.0 = Release|x64
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.Debug|x64.ActiveCfg = Debug|x64
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.Debug|x64.Build.0 = Debug|x64
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.Release|x64.ActiveCfg = Release|x64
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.Release|x64.Build.0 = Release|x64
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.ActiveCfg = Debug|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.Build.0 = Debug|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x64.ActiveCfg = Release|x64
@@ -69,14 +71,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
@@ -93,6 +87,22 @@ Global
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x64.Build.0 = Release|x64
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.Build.0 = Release|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.Debug|x64.ActiveCfg = Debug|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.Debug|x64.Build.0 = Debug|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.MinSizeRel|x64.ActiveCfg = Debug|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.MinSizeRel|x64.Build.0 = Debug|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.Release|x64.ActiveCfg = Release|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.Release|x64.Build.0 = Release|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.RelWithDebInfo|x64.Build.0 = Release|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Debug|x64.ActiveCfg = Debug|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Debug|x64.Build.0 = Debug|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.MinSizeRel|x64.ActiveCfg = Debug|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.MinSizeRel|x64.Build.0 = Debug|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Release|x64.ActiveCfg = Release|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Release|x64.Build.0 = Release|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.RelWithDebInfo|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+55 -52
View File
@@ -1,52 +1,55 @@
<Project>
<PropertyGroup>
<ComputerSpecificConfig>..\..\tools\override\$(computername).props</ComputerSpecificConfig>
<SparkRoot>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)\..\..))</SparkRoot>
<SourceRoot>$([System.IO.Path]::GetFullPath($(SparkRoot)\src))</SourceRoot>
<Externals>$(SparkRoot)\externals\windows</Externals>
<DepotName>$([System.IO.Path]::GetFileName($([System.IO.Path]::GetFullPath($(SparkRoot)))))</DepotName>
<ErrorReport>None</ErrorReport>
<Prefer32Bit>False</Prefer32Bit>
<Deterministic>true</Deterministic>
<EnableDefaultContentItems>False</EnableDefaultContentItems>
<ShowMissingItemTypes>false</ShowMissingItemTypes>
<Configuration Condition="'$(configuration)'==''">Debug</Configuration>
</PropertyGroup>
<PropertyGroup Label="Output">
<BaseOutputPath>$(SparkRoot)\build\$(Configuration)</BaseOutputPath>
<OutputPath>$(BaseOutputPath)\bin</OutputPath>
<BaseIntermediateOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</IntermediateOutputPath>
<GenDir>$(BaseOutputPath)\gen\$(MSBuildProjectName)</GenDir>
</PropertyGroup>
<Import
Project="$(ComputerSpecificConfig)"
Condition="Exists($(ComputerSpecificConfig))" />
<PropertyGroup Label="ProtoBuf">
<ProtocPluginBase>$(SparkRoot)\src\lib\api\service_compiler</ProtocPluginBase>
<protoc>$(Externals)\bin\protoc.exe</protoc>
<protogen>$(Externals)\bin\protogen.exe</protogen>
</PropertyGroup>
<ItemDefinitionGroup>
<Proto2></Proto2>
<Proto3>
<OutBase>$(IntermediateOutputPath)\gen\%(relativedir)</OutBase>
<OutCS>%(OutBase)%(FileName).cs</OutCS>
<OutCSClient>%(OutBase)%(FileName).client.pb.cs</OutCSClient>
<OutCSServer>%(OutBase)%(FileName).server.pb.cs</OutCSServer>
<OutCSImmutable>%(OutBase)%(FileName).immutable.pb.cs</OutCSImmutable>
<CompileOptions></CompileOptions>
</Proto3>
<Proto3Excel>
<OutBase>$(IntermediateOutputPath)\gen\%(relativedir)</OutBase>
<OutCSExcel>%(OutBase)%(FileName).excel.pb.cs</OutCSExcel>
<CompileOptions></CompileOptions>
</Proto3Excel>
</ItemDefinitionGroup>
</Project>
<Project>
<PropertyGroup>
<ComputerSpecificConfig>..\..\tools\override\$(computername).props</ComputerSpecificConfig>
<SparkRoot>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)\..\..))</SparkRoot>
<SourceRoot>$([System.IO.Path]::GetFullPath($(SparkRoot)\src))</SourceRoot>
<Externals>$(SparkRoot)\externals\windows</Externals>
<DepotName>$([System.IO.Path]::GetFileName($([System.IO.Path]::GetFullPath($(SparkRoot)))))</DepotName>
<ErrorReport>None</ErrorReport>
<Prefer32Bit>False</Prefer32Bit>
<Deterministic>true</Deterministic>
<EnableDefaultContentItems>False</EnableDefaultContentItems>
<ShowMissingItemTypes>false</ShowMissingItemTypes>
<Configuration Condition="'$(configuration)'==''">Debug</Configuration>
<EnablePreviewFeatures>true</EnablePreviewFeatures>
<LangVersion>11</LangVersion>
</PropertyGroup>
<PropertyGroup Label="Output">
<BaseOutputPath>$(SparkRoot)\build\$(Configuration)</BaseOutputPath>
<OutputPath>$(BaseOutputPath)\bin</OutputPath>
<BaseIntermediateOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</IntermediateOutputPath>
<ProtoOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</ProtoOutputPath>
<GenDir>$(BaseOutputPath)\gen\$(MSBuildProjectName)</GenDir>
</PropertyGroup>
<Import
Project="$(ComputerSpecificConfig)"
Condition="Exists($(ComputerSpecificConfig))" />
<PropertyGroup Label="ProtoBuf">
<ProtocPluginBase>$(SparkRoot)\src\lib\api\service_compiler</ProtocPluginBase>
<protoc>$(Externals)\bin\protoc.exe</protoc>
<protogen>$(Externals)\bin\protogen.exe</protogen>
</PropertyGroup>
<ItemDefinitionGroup>
<Proto2></Proto2>
<Proto3>
<OutBase>$(IntermediateOutputPath)\gen\%(relativedir)</OutBase>
<OutCS>%(OutBase)%(FileName).cs</OutCS>
<OutCSClient>%(OutBase)%(FileName).client.pb.cs</OutCSClient>
<OutCSServer>%(OutBase)%(FileName).server.pb.cs</OutCSServer>
<OutCSImmutable>%(OutBase)%(FileName).immutable.pb.cs</OutCSImmutable>
<CompileOptions></CompileOptions>
</Proto3>
<Proto3Excel>
<OutBase>$(IntermediateOutputPath)\gen\%(relativedir)</OutBase>
<OutCSExcel>%(OutBase)%(FileName).excel.pb.cs</OutCSExcel>
<CompileOptions></CompileOptions>
</Proto3Excel>
</ItemDefinitionGroup>
</Project>
+11 -2
View File
@@ -52,8 +52,7 @@
<Exec Command="set PYTHONPATH=$(SparkRoot)\.venv\Scripts\python" />
<Exec
Command="
$(SparkRoot)\tools\build_protos.cmd ^
%(Proto3.FullPath) ^
$(protoc) %* %(Proto3.FullPath) ^
--error_format=msvs ^
--proto_path=$(SourceRoot) ^
--plugin=&quot;protoc-gen-service=$(ProtocPluginBase)\plugin.cmd&quot; ^
@@ -68,6 +67,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,17 @@
using mbts.ui.utility;
using mbts.utils;
using Spark.Core;
using Spark.Core.Collections;
using Spark.Core.Disposables;
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;
@@ -26,70 +35,93 @@
class AnalyticsExpirationParametersVM : DisposableViewModelBase, IHandleRowSelection {
readonly IBus _bus;
readonly ObservableCollection<AnalyticsExpirationParameters> _parameters = new();
readonly DeferrableActionWrapper _sync_visible_rows;
readonly Property<AnalyticsExpirationParametersRowVM> _copy_row_source;
readonly DeferrableAction _sync_visible_rows;
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 DeferrableAction _raise_selected_rows_changed;
readonly IRaiseCanExecuteChangedCommand _set_driver_to_nearest_exp_cmd;
IList<string>? _pending_selected_symbols;
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) {
if (!startup_data.selected_symbols.is_null_or_empty()) {
selected_symbols.AddRange(startup_data.selected_symbols);
}
_pending_selected_symbols = startup_data.selected_symbols;
auto_copy_rolls_is_checked = startup_data.auto_copy_rolls_is_checked;
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.Invoke()),
ObservableAutoWrapper.connect(_parameters, rows, p => new(this, p), r => r.Dispose()),
rows.Subscribe((s, e) => _sync_visible_rows.execute()),
ObservableAutoWrapper.connect(
non_options,
explicit_drivers,
sec => new ExpirationDriverImmutable(new() { Security = sec.to_api_sec_exp() })),
rows.Subscribe((s, e) => _sync_visible_rows.Invoke()),
_bus.subscribe(SparkTags.ExpirationParametersInputTag).OnDispatcher().Subscribe(
CompositeObserver.create(
Observer.Create<AnalyticsExpirationParametersMap>(_on_parameter_map),
can_commit_observer.wrap<bool, AnalyticsExpirationParametersMap>(m => m is not null))),
ObservableAutoWrapper.connect_item_hooks(selected_symbols, sym => {
if (selected_symbol_ref_count.increment_adds_key(sym)) {
_sync_visible_rows.execute();
_sync_visible_rows.Invoke();
}
return Disposable.Create(() => {
if (selected_symbol_ref_count.decrement_removes_key(sym)) {
_sync_visible_rows.execute();
_sync_visible_rows.Invoke();
}
});
}),
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(() => {
rows.DisposeAll();
_smart_copy_roll_target_to_selection_cmd?.can_exe_sub?.Dispose();
_smart_copy_riskless_rate_to_selection_cmd?.can_exe_sub?.Dispose();
}));
}
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 +132,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 +181,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 +195,38 @@
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) {
Func<ExpirationDriverImmutable, bool> is_unexpired = (d) => {
var st = d.Security.to_sec_exp().security_tuple.to_api_sec_tuple();
var exp = d.Security.Expiration.date_time();
return SecurityExpirationHelper.is_unexpired(st, exp);
};
foreach (var r in rows) {
if (drivers
.Where(d => d.HasSecurity && d.Security.Symbol == r.security.symbol)
.Where(d => is_unexpired(d))
.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 +235,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 +276,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)) {
@@ -223,10 +294,10 @@
}
symbols.sync_with(_parameters.Select(p => p.security.symbol).Distinct().Ordered());
using var _ = _sync_visible_rows.defer_execution();
using var _ = _sync_visible_rows.defer();
if (is_first_update) {
// select all symbols on first update
selected_symbols.sync_with(symbols);
selected_symbols.sync_with(_pending_selected_symbols?.Intersect(symbols) ?? symbols);
_pending_selected_symbols = null;
}
}
@@ -9,18 +9,18 @@
xmlns:u="clr-namespace:mbts.ui"
xmlns:cv="clr-namespace:mbts.ui.converters"
xmlns:shell="clr-namespace:mbts.ui.shell"
Background="{StaticResource CommonBackground}">
Background="{u:BTSBrush UI.common_background}">
<UserControl.Resources>
<cv:DoubleTextConverter x:Key="DoubleTextConverter" />
<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>
@@ -124,17 +153,23 @@
SelectedItems="{Binding selected_symbols}"
HorizontalAlignment="Left"
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:" />
<TextBlock
Margin="5,5,0,0" Foreground="{u:BTSBrush UI.default_text}" Text="Auto copy rolls:" />
<CheckBox Margin="5,5,10,0" IsChecked="{Binding auto_copy_rolls_is_checked}" />
</WrapPanel>
<WrapPanel>
<TextBlock Margin='0,5,0,0' Text="Auto copy rates:" />
<TextBlock
Margin='0,5,0,0' Foreground="{u:BTSBrush UI.default_text}" Text="Auto copy rates:" />
<CheckBox Margin="5,5,0,0" IsChecked="{Binding auto_copy_rates_is_checked}" />
</WrapPanel>
</StackPanel>
@@ -142,8 +177,8 @@
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 +191,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 +207,7 @@
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</c:DataGridEx.RowStyle>
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter
@@ -209,9 +219,6 @@
<Setter
Property="HorizontalContentAlignment"
Value="Center" />
<Setter
Property="BorderThickness"
Value="0,0,1,0" />
<Setter
Property="BorderBrush"
Value="Black" />
@@ -226,7 +233,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 +245,6 @@
<Setter
Property="Foreground"
Value="{u:BTSColor Name=header_text}" />
<Setter
Property="BorderThickness"
Value="0" />
<Setter
Property="VerticalContentAlignment"
Value="Center" />
@@ -287,9 +291,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 +299,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 +320,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 +359,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 +396,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 +407,15 @@
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" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
@@ -414,9 +431,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 +442,14 @@
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}}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
@@ -448,9 +465,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 +476,14 @@
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}}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
@@ -483,9 +500,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 +511,14 @@
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}}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
@@ -518,9 +535,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,10 +543,11 @@
<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>
@@ -1,10 +1,14 @@
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 Spark.Core.Disposables;
using System;
using System.Windows;
using System.Windows.Controls;
@@ -16,8 +20,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 +35,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 +73,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,13 @@
namespace mbts.spark {
namespace mbts.spark {
using bts.api;
using bts.spark;
using mbts.ui;
using mbts.ui.shell;
using Spark.Core.Disposables;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
@@ -38,11 +41,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,69 @@
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 Spark.Core.Disposables;
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) {
Func<AnalyticsExpirationParameters, bool> is_unexpired = (p) => {
var st = p.driver_security.security_tuple.to_api_sec_tuple();
var exp = p.security.expiration;
return SecurityExpirationHelper.is_unexpired(st, exp);
};
exp_params = exp_params.Where(t => is_unexpired(t));
// 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));
@@ -63,9 +63,9 @@ namespace mbts.spark {
vs_input, vs_nonvol_data.contracts, aux_data_map);
_timer.stop();
var tag_str = tag == null ? "Null" : tag.ToString();
bts.Log.Gen.info($"SingleVolSurfaceCommittedOutputRetriever._recompute_and_publish " +
$"vs_id: {_vs_id} time:{_timer.lastIntervalTime} ms tag:{tag_str} " +
$"tid:{_tid()}"); //output: {vs_output.log_string()}*/");
// bts.Log.Gen.info($"SingleVolSurfaceCommittedOutputRetriever._recompute_and_publish " +
// $"vs_id: {_vs_id} time:{_timer.lastIntervalTime} ms tag:{tag_str} " +
// $"tid:{_tid()}"); //output: {vs_output.log_string()}*/");
_logger.log(_log_id, _log_id, _timer.lastIntervalTime);
_bb.post(_out_bb_computed_vol_tag, vs_output);
}
@@ -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)) {
@@ -75,7 +75,7 @@ namespace mbts.spark {
var exp_price_map = OptionDriverPriceMap.get_vs_price_map(
all_sym_price_map, (s) => _option_symbols.Contains(s));
if (sc_data != null && vs_nonvol_input != null && exp_price_map != null) {
bts.Log.Gen.info($"SingleVolSurfaceNonVolDataSource vs_id:{_vs_id} " +
bts.Log.Gen.diag($"SingleVolSurfaceNonVolDataSource vs_id:{_vs_id} " +
"publishing VolSurfaceNonVolData");
_bb.post(_out_bb_vs_nonvol_data_tag,
new VolSurfaceNonVolData(
@@ -32,7 +32,7 @@ namespace mbts.spark {
public SingleVolSurfaceRequestCalculator(int vs_id, IEnumerable<string> symbols,
ThreadedBlackboard threaded_bb) {
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator cons vs_id:{vs_id}");
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator cons vs_id: {vs_id}");
_vs_id = vs_id;
_symbols = new HashSet<string>(symbols);
_bb = threaded_bb;
@@ -89,8 +89,8 @@ namespace mbts.spark {
effective_req.cascade_up,
effective_req.cascade_down);
_timer.stop();
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._recompute_and_publish time:" +
$"{_timer.lastIntervalTime} vs_output:{_last_output.log_string()}");
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._recompute_and_publish time: " +
$"{_timer.lastIntervalTime}");
_bb.post(SparkTags.VolSurfaceCalculationResponseTag(_vs_id),
new VolSurfaceCalculationResponse(_last_output, effective_req.request_id));
}
@@ -11,18 +11,22 @@ namespace mbts.analytics {
// tags, into IReadOnlyDictionary of symbol vs data publsihed under one tag
public class SymbolAggregationPublisher<TData> : IDisposable {
private readonly ThreadedBlackboard _bb;
private readonly ITag<SystemContractData> _sc_data_tag;
private readonly SecurityType _sec_type;
Func<string, ITag<TData>> _get_tag;
// the tag on which the output will be published
ITag<IReadOnlyDictionary<string, TData>> _out_tag;
private readonly ITag<SystemContractData> _sc_data_tag;
private Dictionary<string, ITag<TData>> _tag_map =
new Dictionary<string, ITag<TData>>();
private HashSet<object> _obj_tags = new HashSet<object>();
private bool _dirty = true;
public SymbolAggregationPublisher(
ThreadedBlackboard bb,
SecurityType sec_type,
Func<string, ITag<TData>> get_tag,
ITag<IReadOnlyDictionary<string, TData>> out_tag) {
_bb = bb;
_sec_type = sec_type;
_get_tag = get_tag;
_out_tag = out_tag;
_sc_data_tag = SparkTags.SystemContractsTag;
@@ -48,15 +52,20 @@ namespace mbts.analytics {
return;
}
foreach (var st in sc_data.sectup_map) {
if (st.security_type != _sec_type) {
continue;
}
// this is not correct since it is assuming symbol/name is
// unique across securty_tuples
string symbol = st.security_name;
if (!_tag_map.ContainsKey(symbol)) {
var symbol_tag = _get_tag(symbol);
_tag_map.Add(symbol, symbol_tag);
_obj_tags.Add(symbol_tag);
_bb.subscribe(symbol_tag);
_dirty = true;
var tag = _get_tag(symbol);
if (tag != null) {
_tag_map.Add(symbol, tag);
_obj_tags.Add(tag);
_bb.subscribe(tag);
_dirty = true;
}
}
}
}
@@ -72,7 +81,7 @@ namespace mbts.analytics {
output.Add(symbol, symbol_data);
}
IReadOnlyDictionary<string, TData> ro_output = output;
bts.Log.Gen.info($"SymbolAggregationPublisher._on_timer publishing " +
bts.Log.Gen.diag($"SymbolAggregationPublisher._on_timer publishing " +
$"tag: {_out_tag} sz: {ro_output.Count}");
_bb.post(_out_tag, ro_output);
}
@@ -15,6 +15,8 @@ using System.Reactive.Linq;
using System.Collections;
using mbts.spark;
using System.DirectoryServices.ActiveDirectory;
using Spark.Core.Protobuf;
using mbts.ui;
// using mbts.bb;
namespace mbts.spark {
@@ -53,6 +55,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
@@ -74,10 +77,11 @@ namespace mbts.spark {
private HighPerformanceTimer _timer = new HighPerformanceTimer();
public VolSurfaceBusManager(bts.api.IBus bus,
bts.api.analytics.AnalyticsService analytics_service) {
bts.api.analytics.AnalyticsService analytics_service,
bts.api.orderman.OrderService order_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,48 +100,121 @@ 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),
_bb, SecurityType.Option, sym => SparkTags.OptionDriverBBOTag(sym),
SparkTags.AllOptionDriverBBOTag));
_subs.Add(new SymbolAggregationPublisher<OptionTheoInterpolationData>(
_bb, (sym) => SparkTags.SymbolInterpGreeksTag(sym),
_bb, SecurityType.Option, sym => SparkTags.SymbolInterpGreeksTag(sym),
SparkTags.AllInterpGreeks));
_subs.Add(new SymbolAggregationPublisher<ExpStrikeKeyedData<TheoPoint>>(
_bb, SecurityType.Option, sym => SparkTags.TC2Tags.LiveTheosTag(sym),
SparkTags.TC2Tags.AllLiveTheosTag));
_subs.Add(new LiveTheoPublisher(_bb));
_subs.Add(new InterpTheosServerPublisher(_bb, order_service));
_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);
_spin_vss(list_imm);
});
_bb.post(SparkTags.VolSurfaceUsageTag, new VolSurfaceUsageListImmutable(ulist));
_disps.Add(list_sub);
// f(contract keyed theos, securities) -> id keyed theos
// (so the newer UI controls can access theos vis sec keys)
var theo_sub =
_bus.subscribe(SparkTags.TC2Tags.AllLiveTheosTag)
.CombineLatest(bus.subscribe(SparkTags.SystemContractsTag),
(theos, sc_data) => (theos, sc_data)).Subscribe(
tup => {
var keyed_theos = _assemble_keyed_theos(tup.sc_data, tup.theos);
_bus.post(SparkTags.KeyedTheos, keyed_theos);
}
);
_disps.Add(theo_sub);
}
static IReadOnlyDictionary<uint, VolSurfaceTheoPoint> _assemble_keyed_theos(
SystemContractData sc_data,
IReadOnlyDictionary<string, ExpStrikeKeyedData<TheoPoint>> theos) {
if (sc_data is null || theos is null) {
return new Dictionary<uint, VolSurfaceTheoPoint>(0);
}
HighPerformanceTimer timer = new HighPerformanceTimer();
timer.start();
Dictionary<uint, VolSurfaceTheoPoint> rv = new Dictionary<uint, VolSurfaceTheoPoint>();
foreach (var kv in theos) {
var symbol = kv.Key;
ExpStrikeKeyedData<TheoPoint> sym_theos = kv.Value;
if (sym_theos == null)
continue;
foreach (var s_kv in sym_theos.get_data_linearly()) {
DateTime exp = s_kv.first;
double strike = s_kv.second;
TheoPoint tp = s_kv.third;
// TODO: fix exchange later
Tuple<uint?, uint?> keys =
sc_data.get_option_sec_id(Venue.Deribit, symbol, exp, strike);
if (keys != null) {
var c_key = keys.Item1;
var p_key = keys.Item2;
if (c_key.HasValue) {
rv[c_key.Value] = new VolSurfaceTheoPoint(tp, true);
}
if (p_key.HasValue) {
rv[p_key.Value] = new VolSurfaceTheoPoint(tp, false);
}
}
}
}
timer.stop();
Log.Gen.info($"VolSurfaceBusManager keyed theos count: {rv.Count} " +
$"time: {timer.lastIntervalTime}");
return rv;
}
public ThreadedBlackboard bb() {
return _bb;
}
void _spin_vss(VolSurfaceUsageListImmutable ulist) {
foreach (var u in ulist.UsageList) {
var vs_id = u.VsId;
_bb.post(SparkTags.VolSurfaceActiveUITag(vs_id), true);
}
}
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 +249,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;
@@ -0,0 +1,20 @@
namespace mbts.analytics {
using mbts.spark;
// TheoPoint (from edge) has both calls and puts in the same structure.
// This shoudl dis-entangle that
public class VolSurfaceTheoPoint {
public readonly double theo = double.NaN;
public readonly double delta = double.NaN;
public readonly double driver = double.NaN;
public VolSurfaceTheoPoint(TheoPoint tp, bool is_call) {
if (tp != null) {
theo = is_call ? tp.fwd_normalized_call : tp.fwd_normalized_put;
delta = is_call ? tp.cdelta : tp.pdelta;
driver = tp.driver;
}
}
}
}
@@ -6,6 +6,7 @@
using mbts.user.settings;
using System;
using System.Collections.Generic;
public class VolSurfaceDisplayGridColumn : IEquatable<VolSurfaceDisplayGridColumn> {
public readonly Func<object, string> format;
@@ -18,16 +19,19 @@
VolSurfaceColumnSettings settings,
Func<object, string> format = null,
Func<string, object> parse = null,
Func<object, bool, object> tick_move = null) {
Func<object, bool, object> tick_move = null,
IEqualityComparer<object> comparer = null) {
this.settings = settings;
this.format = format ?? (v => v?.ToString() ?? string.Empty);
this.parse = parse ?? (v => v);
this.tick_move = tick_move ?? ((v, is_up) => v);
this.comparer = comparer ?? EqualityComparer<object>.Default;
}
public string unique_col_name => settings.id;
public string display_name => settings.display_name;
public string group => settings.group;
public IEqualityComparer<object> comparer { get; }
internal VolSurfaceColumnType type => settings.type;
@@ -7,6 +7,7 @@
using mbts.user.settings;
using System;
using System.Collections.Generic;
class VolSurfaceDisplayUtilities {
public static TickDisplaySettings default_tick_display =>
@@ -18,6 +19,10 @@
default_tick_display.with(display_multiplier: 100);
public static double parse_double(object obj) {
if (obj is null) {
Log.Gen.warn("parse_double received null input (will return nan and continue)");
return double.NaN;
}
Log.assert(obj is double);
obj = obj ?? Double.NaN;
double rv = obj is Double ? (double)obj : (Double.TryParse(obj.ToString(), out rv) ? rv : Double.NaN);
@@ -49,9 +54,31 @@
}
public static Func<object, bool, object> get_double_tickmove(TickFactors tick_factors, int tick_move) =>
(data, is_up) => data is double d_data ?
tick_factors.tick(d_data, is_up ? tick_move : -tick_move) :
data;
(data, is_up) => {
if (data is not double dbl) {
return data;
}
if (dbl.is_nan()) {
return 0D;
}
return tick_factors.tick(dbl, is_up ? tick_move : -tick_move);
};
public static IEqualityComparer<double> get_double_comparer(
TickFactors tick_factors = null, double display_mult = double.NaN) {
if (tick_factors is null) {
return new TickFactors(10^7, 1).tick_equality_comparer();
}
// This equality comparer is used to compare actual values (not multiplied by
// 'display_mult'), while the TickFactors are used to format the display value (multiplied
// by 'display_mult'). Multiply the tick base by 'display_mult' so the equality comparison
// is done with the correct number of decimal places.
if (display_mult > 0 && Math.Log10(display_mult).is_int()) {
tick_factors = tick_factors.with(
tick_base: tick_factors.tick_base * display_mult);
}
return tick_factors.tick_equality_comparer();
}
public static VolSurfaceDisplayGridColumn get_double_output_col(
string group,
@@ -113,7 +140,10 @@
col_config,
format: get_double_tostring(col_config.tick_factors, col_config.tick_display),
parse: get_parse_double(col_config.tick_factors, col_config.tick_display),
tick_move: get_double_tickmove(col_config.tick_factors, col_config.tick_move));
tick_move: get_double_tickmove(col_config.tick_factors, col_config.tick_move),
comparer: get_double_comparer(
col_config.tick_factors, col_config.tick_display.display_multiplier)
.cast<double, object>());
}
}
}
@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using mbts.analytics;
using bts.api;
using bts.collections;
using System.Linq;
using bts.api.orderman;
using bts;
namespace mbts.spark {
// Listens to the interp theos, decorates the data
// and sends them over to the sparkd server
public class InterpTheosServerPublisher : IDisposable {
private readonly ThreadedBlackboard _bb;
private readonly bts.api.orderman.OrderService _order_service;
private HighPerformanceTimer _timer = new HighPerformanceTimer();
public InterpTheosServerPublisher(ThreadedBlackboard bb,
bts.api.orderman.OrderService order_service) {
bts.Log.Ui.info(
$"InterpTheosServerPublisher cons tid:{VolSurfaceTroubleshootingFunctions.tid()}");
_bb = bb;
_order_service = order_service;
_bb.subscribe(SparkTags.AllInterpGreeks);
_bb.subscribe(SparkTags.SystemContractsTag);
_bb.data_callback += _on_data;
}
private void _on_data(object tag, object data) {
if (tag.Equals(SparkTags.SystemContractsTag) ||
tag.Equals(SparkTags.AllInterpGreeks)) {
_publish_data();
}
}
private static IDictionary<UInt32, DriverMD> _get_drivers(
IReadOnlyDictionary<string, OptionDriverPriceMap> driver_map,
SystemContractData sc_data) {
var rv = new Dictionary<UInt32, DriverMD>();
foreach (var kv in driver_map) {
rv.AddRange(
SecurityNormalizer.normalize_drivers(kv.Value, sc_data).ToArray());
}
return rv;
}
private static IEnumerable<Tuple<SecurityImmutable, TheoPoint>> _get_theos(
IReadOnlyDictionary<string, OptionTheoInterpolationData> theo_data,
SystemContractData sc_data) {
var rv = new List<Tuple<SecurityImmutable, TheoPoint>>();
foreach (var kv in theo_data) {
rv.AddRange(
SecurityNormalizer.normalize_interp_theos(kv.Value, sc_data));
}
return rv;
}
private void _publish_data() {
SystemContractData sc_data = _bb.read_state(SparkTags.SystemContractsTag, null);
IReadOnlyDictionary<string, OptionTheoInterpolationData> all_theos =
_bb.read_state(SparkTags.AllInterpGreeks, null);
IReadOnlyDictionary<string, OptionDriverPriceMap> all_drivers =
_bb.read_state(SparkTags.AllOptionDriverBBOTag, null);
if (sc_data == null || all_theos == null || all_drivers == null)
return;
_timer.start();
IDictionary<UInt32, DriverMD> driver_map = _get_drivers(all_drivers, sc_data);
IEnumerable<Tuple<SecurityImmutable, TheoPoint>> theo_map = _get_theos(all_theos, sc_data);
// assemble it together and send it to the server
var ptp_list = new List<bts.api.orderman.PrecomputedTheoPoint>();
foreach (var tup in theo_map) {
SecurityImmutable sec = tup.Item1;
TheoPoint tp = tup.Item2;
bool is_call = sec.Option.CallPut == PutOrCall.Call;
var sec_id = sec.Id;
DriverMD dmd = null;
driver_map.TryGetValue(sec_id, out dmd);
PrecomputedTheoPoint ptp = new PrecomputedTheoPoint();
ptp.SecId = sec_id;
ptp.Driver = tp.driver;
ptp.DriverSecId = dmd != null && dmd.driver_security.HasValue ?
dmd.driver_security.Value.Id : 0;
ptp.Theo = is_call ? tp.call : tp.put;
ptp.Delta = is_call ? tp.cdelta : tp.pdelta;
ptp.Gamma = is_call ? tp.cgamma : tp.pgamma;
ptp.Vega = is_call ? tp.cvega : tp.pvega;
ptp.Theta = is_call ? tp.c_theta : tp.p_theta;
ptp.Rho = Double.NaN;
ptp_list.Add(ptp);
}
bts.api.orderman.PrecomputedTheos server_theos = new PrecomputedTheos();
server_theos.Theos.AddRange(ptp_list);
_timer.stop();
var comp_time = _timer.lastIntervalTime;
_timer.start();
_order_service.set_precomputed_theos(server_theos);
_timer.stop();
var pub_time = _timer.lastIntervalTime;
bts.Log.Gen.info($"InterpTheosServerPublisher._publish_data " +
$"size: {server_theos.Theos.Count} comp_time: {comp_time} msecs " +
$"pub_time: {pub_time}");
}
public void Dispose() {
_bb.data_callback -= _on_data;
}
}
}
+80 -17
View File
@@ -3,6 +3,10 @@ using System.Collections.Generic;
using mbts.analytics;
using bts.api;
using mbts.ui;
using MathNet.Numerics.Providers.FourierTransform;
using BCG;
using System.Windows.Automation;
using bts.collections;
namespace mbts.spark {
// Publishes theos for all options (on the side, also publishes the theos for TC2)
@@ -15,12 +19,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 +38,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;
@@ -59,19 +70,14 @@ namespace mbts.spark {
}
private void _log_theos(SystemContractData sc_data,
IReadOnlyDictionary<uint, GreeksTuple> greeks_map,
DateTime? exp_filt = null) {
IReadOnlyDictionary<uint, GreeksTuple> greeks_map) {
string rv = "LiveTheosPublisher data: ";
foreach (var kv in greeks_map) {
var id = kv.Key;
var g_tup = kv.Value;
if (sc_data.sec_md_map.TryGetValue(id, out var smd)) {
if (exp_filt == null ||
(smd.security.security_type() == SecurityType.Option &&
smd.security.Option.expiration_date().Equals(exp_filt.Value))) {
string sec_str = smd.ToString();
rv += "\n" + $"id: {id} sec: {sec_str} greeks: {g_tup}";
}
string sec_str = smd.ToString();
rv += "\n" + $"id: {id} sec: {sec_str} greeks: {g_tup}";
}
}
bts.Log.Gen.info(rv);
@@ -125,36 +131,93 @@ namespace mbts.spark {
return;
}
var k_theos = new Dictionary<SecurityStrike, TheoPoint>();
// option spreads
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) {
var normalized_theo = VolSurfaceCoreFunctions.normalize_theo(tp.call, tp.driver);
res.Add(call_id.Value,
new GreeksTuple(tp.vol, tp.driver, tp.call, tp.cdelta, tp.cgamma,
tp.cvega, tp.c_theta, Double.NaN));
tp.cvega, tp.c_theta, Double.NaN, normalized_theo));
}
if (cp_id.Item2.HasValue) {
res.Add(cp_id.Item2.Value,
if (put_id.HasValue) {
var normalized_theo = VolSurfaceCoreFunctions.normalize_theo(tp.put, tp.driver);
res.Add(put_id.Value,
new GreeksTuple(tp.vol, tp.driver, tp.put, tp.pdelta, tp.pgamma,
tp.pvega, tp.p_theta, Double.NaN));
tp.pvega, tp.p_theta, Double.NaN, normalized_theo));
}
}
}
// futures
var future_theos = _get_future_theos();
res.AddRange(future_theos);
// spreads, all option and future non tied spreads
foreach (var spr in sc_data.spreads) {
GreeksTuple gtup = StatelessSpreadCalculator.compute_non_tied_spread(spr.security, res);
res.Add(spr.security.Id, gtup);
}
// copy and publish
IReadOnlyDictionary<uint, GreeksTuple> res_ro = res;
bts.Log.Gen.info($"LiveTheoPublisher._interp_and_publish posting " +
$"count: {res_ro.Count}");
$"count: {res_ro.Count}");
_timer.stop();
_logger.log(_log_id, _log_id, _timer.lastIntervalTime);
_bb.post(SparkTags.Greeks, res_ro);
// oh and those TC2 theos for comptability
_publish_tc2_theos(k_theos);
}
// If we do any rolls like SP for futures, it will be here
IDictionary<UInt32, GreeksTuple> _get_future_theos() {
var rv = new Dictionary<UInt32, GreeksTuple>();
SystemContractData sc_data = _bb.read_state(SparkTags.SystemContractsTag);
if (sc_data == null)
return rv;
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(sec_md.security.Id,
new GreeksTuple(0, pr, pr, 1, 0, 0, 0, 0, pr));
}
}
}
return rv;
}
// 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,50 @@
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 bts.api;
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);
}
public IReadOnlyDictionary<SecurityExpiration, DriverMD> get_price_map() {
return new Dictionary<SecurityExpiration, DriverMD>(exp_price_map);
}
}
}
}
@@ -0,0 +1,70 @@
namespace mbts.spark {
using bts.api;
using System;
using System.Collections.Generic;
using System.Linq;
// A lot of options data (migrated from edge) is not normalized
// on the sec_id, but rather on a combination of symbol, exp, strike.
// Additionally the exchange is missing. This class serves as that
// one since point to resolve that.
// (Over time we will normalize all the data and this wont be needed)
public static class SecurityNormalizer {
// f(option_exp:driver_md) -> (sec_id:driver_md)
public static IDictionary<UInt32, DriverMD> normalize_drivers(
OptionDriverPriceMap driver_map, SystemContractData sc_data) {
if (driver_map is null) {
return new Dictionary<uint, DriverMD>(0);
}
Dictionary<UInt32, DriverMD> rv = new Dictionary<uint, DriverMD>();
foreach (var kv in driver_map.get_price_map()) {
var exp = kv.Key;
var dmd = kv.Value;
IEnumerable<SecurityMD> exp_secs = sc_data.get_securities(
(sec_md) => {
var s = sec_md.security;
return s.security_type() == SecurityType.Option &&
s.Symbol == driver_map.option_symbol &&
s.earliest_expiration() == exp.expiration;
}
);
foreach (var sec_md in exp_secs) {
rv.Add(sec_md.security.Id, kv.Value);
}
}
return rv;
}
public static IEnumerable<Tuple<SecurityImmutable, TheoPoint>> normalize_interp_theos(
OptionTheoInterpolationData symbol_theos, SystemContractData sc_data) {
if (symbol_theos is null) {
return Enumerable.Empty<Tuple<SecurityImmutable, TheoPoint>>();
}
var rv = new List<Tuple<SecurityImmutable, TheoPoint>>();
foreach (DateTime exp in symbol_theos.get_expirations()) {
Dictionary<double, Dictionary<double, TheoPoint>> exp_data =
symbol_theos.get_expiration_data(exp);
// exp_data is driver vs strike vs TP
foreach (var exp_kv in exp_data) {
foreach (var k_kv in exp_kv.Value) {
double strike = k_kv.Key;
TheoPoint tp = k_kv.Value;
IEnumerable<SecurityMD> calls = sc_data.get_options(
null, symbol_theos.symbol, exp, strike, PutOrCall.Call);
IEnumerable<SecurityMD> puts = sc_data.get_options(
null, symbol_theos.symbol, exp, strike, PutOrCall.Put);
foreach (SecurityMD sec_md in calls) {
rv.Add(Tuple.Create(sec_md.security, tp));
}
foreach (SecurityMD sec_md in puts) {
rv.Add(Tuple.Create(sec_md.security, tp));
}
}
}
}
return rv;
}
}
}
@@ -1,4 +1,5 @@
using System;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
@@ -107,6 +108,22 @@ namespace mbts.spark {
}
}
public SecurityImmutable? get_option_contract(
Venue venue, string symbol, DateTime exp, double strike, PutOrCall cp) {
var k_tup = get_option_sec_id(venue, symbol, exp, strike);
if (k_tup != null) {
var id = cp == PutOrCall.Call ? k_tup.Item1 : k_tup.Item2;
if (id.HasValue) {
var id_val = id.Value;
SecurityMD sec_md;
if (sec_md_map.TryGetValue(id_val, out sec_md)) {
return sec_md.security;
}
}
}
return null;
}
public Tuple<uint?, uint?> get_option_sec_id(
Venue venue, string symbol, DateTime exp, double strike) {
var s_exp = new SecurityExpiration(venue, SecurityType.Option, symbol, exp);
@@ -173,7 +190,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 +199,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));
@@ -243,5 +259,28 @@ namespace mbts.spark {
kv.Value.Count > 0).Select(kv => kv.Key.expiration);
}
public IEnumerable<SecurityMD> spreads {
get {
return sec_md_map.Where(kv => kv.Value.security.HasSpread)
.Select(kv => kv.Value);
}
}
public IEnumerable<SecurityMD> get_securities(Func<SecurityMD, bool> criteria) {
return sec_md_map.Values.Where(sec_md => criteria(sec_md));
}
public IEnumerable<SecurityMD> get_options(
Venue? exchange, string option_name, DateTime? exp, double? strike, PutOrCall? cp) {
return get_securities(sc => {
var s = sc.security;
return s.security_type() == SecurityType.Option &&
(exchange == null || s.Exchange == exchange) &&
(exp == null || s.earliest_expiration() == exp) &&
(strike == null || s.strike() == strike) &&
(cp == null || s.Option.CallPut == cp);
});
}
}
}
@@ -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
@@ -55,6 +63,27 @@ namespace mbts.spark {
return rv;
}
public static string log_string(this VolSurfaceCalculationRequest vs_req) {
if (vs_req == null) {
return "Null";
}
string action_str = String.Empty;
foreach (var kv in vs_req.action_map) {
action_str += $"exp: {kv.Key.ToString()} action: {kv.Value.ToString()}, ";
}
action_str = action_str.TrimEnd(',', ' ');
return $"vs_inp: {vs_req.volsurface_input.log_string()}\nreq_id: {vs_req.request_id}\n" +
$"action_map: {action_str}\nup: {vs_req.cascade_up} down: {vs_req.cascade_down}";
}
public static string log_string(this VolSurfaceCalculationResponse resp) {
if (resp == null) {
return "Null";
}
return $"req_id: {resp.request_id} vs_output: " +
$"{resp.volsurface_calculation_output.volsurface_input.log_string()}";
}
private static string _trim_leading_char(string s, char c) {
if (!s.is_null_or_empty() && s.EndsWith(c)) {
return s.Remove(s.Length - 1, 1);
@@ -63,11 +92,12 @@ namespace mbts.spark {
}
internal static string log_string(this VolSurfaceDisplayModel.DisplayModelData dm_data) {
string rv = String.Empty;
string global_grid_str = dm_data.global_grid == null ? "Null" : dm_data.global_grid.log_string();
rv += $"global_grid: {global_grid_str} \n";
string exp_grid_str = dm_data.exp_grid == null ? "Null" : dm_data.exp_grid.log_string();
rv += $"exp_grid: {exp_grid_str} \n";
var vs_output = dm_data.vs_output;
var exp_grid = dm_data.exp_grid;
var vs_output_str = vs_output == null ? "NULL" : vs_output.volsurface_input.log_string();
var exp_grid_str = exp_grid == null ? "NULL" : exp_grid.log_string();
var rv = $"DisplayModelData\nvs_output:\n{vs_output_str}\n" +
$"exp_grid\n{exp_grid_str}\n";
return rv;
}
@@ -83,19 +113,19 @@ namespace mbts.spark {
}
internal static string log_string(this VolSurfaceDisplayGrid dgrid) {
Func<IDictionary<string, object>, string> log_exp = (map) => {
Func<IDictionary<string, object>, string> log_exp = (col_val_map) => {
string rv = String.Empty;
foreach (var kv in map) {
foreach (var kv in col_val_map) {
string val_string = kv.Value == null ? "Null" : kv.Value.ToString();
rv += $"{kv.Key}:{val_string},";
rv += $"{kv.Key}: {val_string}, ";
}
return _trim_leading_char(rv, ',');
};
string rv = String.Empty;
foreach (var kv in dgrid.data_map) {
rv += $"Exp:{kv.Key.expiration.ToShortDateString()} Data:{log_exp(kv.Value)},";
rv += $"Exp: {kv.Key.expiration.ToShortDateString()} Data: {log_exp(kv.Value)}\n";
}
return _trim_leading_char(rv, ',');
return rv;
}
internal static string log_string(this OptionDriverPriceMap map) {
@@ -132,7 +162,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 +181,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 +208,67 @@ 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 string log_string(this IPNLUnit p) {
string rv = "IPNLUnit:";
rv += $" account: {p.account} sec: {p.security.security_desc()} driver: {p.driver} theo: {p.theo} settle: {p.settle_price}" +
$" start_pos: {p.start_long_pos - p.start_short_pos} day_pos: {p.day_long_pos - p.day_short_pos}" +
$" start_pnl: {p.start_pnl} start_delta: {p.start_delta} start_vega: {p.start_vega}" +
$" day_pnl: {p.day_pnl} day_delta: {p.day_delta} day_vega: {p.day_vega}";
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,15 +3,16 @@ 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;
[ProtoContract]
class VolSurfaceGraphSettings : IEquatable<VolSurfaceGraphSettings>, ICloneable {
class VolSurfaceGraphSettings : IProtobuf<VolSurfaceGraphSettings> {
public static VolSurfaceGraphSettings get_default() {
return new VolSurfaceGraphSettings {
put_control_points = new ScatterSeriesSettings {
@@ -109,8 +110,8 @@ namespace mbts.spark {
// }
//}
public object Clone() =>
ProtoBufSerializationHelper.clone_protobuf(this);
public VolSurfaceGraphSettings Clone() =>
ProtobufSerializationHelper.clone(this);
public bool Equals(VolSurfaceGraphSettings other) =>
other != null &&
@@ -6,6 +6,10 @@ using mbts.analytics;
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.Core;
using Spark.Core.Disposables;
using Spark.Core.Collections;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -51,7 +55,7 @@ namespace mbts.spark {
var vs_removes = removed.Select(exp => exp.ToVSExp());
var true_removed = removed.Where(rmv => !vs_adds.Contains(rmv.ToVSExp()));
var true_added = added.Where(add => !vs_removes.Contains(add.ToVSExp()));
var true_added = added.Except(vs_removes.Concat(_hidden_exps), v => v.ToVSExp());
var changed_calc_modes = added.Where(add => vs_removes.Contains(add.ToVSExp()));
foreach (var tr in true_removed) {
@@ -61,16 +65,10 @@ namespace mbts.spark {
}
}
foreach (var ta in true_added) {
if (_hidden_exps.Contains(ta.ToVSExp()) ||
!rows.TryGetFirst(r => r.expiration.expiration == ta.expiration, out var row)) {
continue;
}
visible_rows.InsertSorted(row,
Comparer<IExpirationBasedRow>.Create(
(r1, r2) => r1.expiration.CompareTo(r2.expiration))
.wrap<IExpirationBasedRow, object>());
}
var comp = ComparerWrapper<object>.wrap_cast(
NullCheckComparer.create<IExpirationBasedRow>(
(r1, r2) => r1.expiration.CompareTo(r2.expiration)));
visible_rows.InsertSorted(true_added, comp);
foreach (var ccm in changed_calc_modes) {
int index = visible_rows
@@ -10,6 +10,10 @@ namespace mbts.spark {
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.Analytics.View;
using Spark.Core.Disposables;
using Spark.Core.Protobuf;
using System;
using System.Collections;
using System.Collections.Generic;
@@ -27,13 +31,13 @@ namespace mbts.spark {
readonly LinearAxisVM _x_axis = new() { position = AxisPosition.BottomLeftToRight };
readonly LinearAxisVM _y_axis = new() { position = AxisPosition.LeftBottomToTop };
readonly Dictionary<SecurityExpiration, ExpGraphBounds> _expiration_graph_bounds;
readonly VolSurfaceGraphSettings _settings;
readonly ObservableCollection<VolSurfaceDisplayGridExpiration> _expirations = new();
readonly Dictionary<VolSurfaceDisplayGridExpiration, SeriesSetVM> _expiration_series_cache = new();
VolSurfaceExpiration _md_exp;
VolSurfaceDisplayGridExpiration _expiration;
VolSurfaceDisplayGridExpiration _earliest_selected_expiration;
VolSurfaceGraphSettings _settings;
object _implied_vol_market_side = ImpliedVolHelper.None;
bool _show_vol_path;
@@ -46,7 +50,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 +64,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;
@@ -78,13 +86,17 @@ namespace mbts.spark {
if (_model.get_active_settings() is not VolSurfaceSettings vss) {
return null;
}
// return new VolSurfaceGraphSettingsEditor {
// DataContext = new VolSurfaceGraphSettingsEditorVM(vss.core_settings.vol_surface_name, ProtoBufSerializationHelper.clone_protobuf(_settings), settings => {
// _settings = settings;
// _recreate_series();
// })
// };
return null;
var vm = new VolSurfaceGraphSettingsVM(vss.core_settings.vol_surface_name);
vm.load_from(_settings.Clone());
vm.request_commit += commit;
return new VolSurfaceGraphSettingsWindow {
DataContext = vm
};
void commit(VolSurfaceGraphSettings settings) {
_settings = settings;
_recreate_series();
}
});
graph_vm = new BTSGraphVM {
plot_area_background = Colors.Transparent,
@@ -113,7 +125,7 @@ namespace mbts.spark {
})
.BufferLatest(TimeSpan.FromSeconds(0.1))
.OnDispatcher()
.SelectManyInSeries(series => Observable.Create<SeriesVM>(o => {
.SelectSeries(series => Observable.Create<SeriesVM>(o => {
o.OnNext(null);
return Disposable.Create(series
.Select(svm => svm.points.Subscribe((s, e) => o.OnNext(svm)))
@@ -181,6 +193,20 @@ namespace mbts.spark {
static (double call_wing_start, double put_wing_start) _get_actual_wing_starts(VolCurveDisplayGraph disp_graph) =>
disp_graph.all_points.Select(p => p.Item1).MinMax() ?? (double.NaN, double.NaN);
void _recreate_series() {
/// 'graph_vm.series_set' is bound to '_expirations', so clearing and re-adding expirations
/// in turn regenerates the series. '_expiration_series_cache' must
/// be cleared as well, otherwise cached series vms would just be back to the collection
/// ('graph_vm.series_set').
var visible_exp = _earliest_selected_expiration;
_expiration_series_cache.Clear();
_expirations.SetItems(_model.get_ordered_expirations());
foreach (var svm in graph_vm.series.OfType<SeriesSetVM>()) {
svm.is_visible = svm.args.Equals(visible_exp);
}
_update();
}
void _expirations_changed(IEnumerable<VolSurfaceDisplayGridExpiration> added, IEnumerable<VolSurfaceDisplayGridExpiration> removed) {
_expirations.sync_with(_model.get_ordered_expirations());
_update();
@@ -1,84 +0,0 @@
namespace mbts.spark {
using mbts.ui;
using mbts.ui.shell;
using System;
using System.Reactive.Linq;
using System.Windows.Input;
class VolGridCellVM : DisposableViewModelBase {
readonly Property<object> _candidate_value;
readonly Property<object> _committed_value;
readonly Property<bool> _is_dirty;
public VolGridCellVM(string column_id) {
this.column_id = column_id ?? throw new ArgumentNullException(nameof(column_id));
_committed_value = backing<object>(nameof(committed_value));
_candidate_value = backing<object>(nameof(candidate_value));
_is_dirty = backing(nameof(is_dirty),
_committed_value.observe_current(true)
.CombineLatest(_candidate_value.observe_current(true))
.Select(tup => !Equals(tup.First, tup.Second))
.OnDispatcher());
}
public string column_id { get; }
public object committed_value {
get => _committed_value.Value;
set => _committed_value.set(value);
}
public object candidate_value {
get => _candidate_value.Value;
set => _candidate_value.set(value);
}
public bool is_dirty => _is_dirty.Value;
public IObservable<object> observe_candidate(bool start_immediately = false) =>
_candidate_value.observe_current(start_immediately);
public void revert() =>
candidate_value = committed_value;
public override string ToString() =>
$"column_id: {column_id}, committed: {committed_value}, candidate: {candidate_value}";
}
class VolGridCellVM<T> : VolGridCellVM {
public VolGridCellVM(string column_id) : base(column_id) { }
public VolGridCellVM(string column_id, T committed_value, T candidate_value) : base(column_id) {
this.committed_value = committed_value;
this.candidate_value = candidate_value;
}
public new T committed_value {
get => base.committed_value is T v ? v : default;
set => base.committed_value = value;
}
public new T candidate_value {
get => base.candidate_value is T v ? v : default;
set => base.candidate_value = value;
}
}
class VolGridTickCellVM : VolGridCellVM {
ICommand _tick_up_cmd;
ICommand _tick_down_cmd;
public VolGridTickCellVM(string column_id) : base(column_id) { }
public event Action<bool> request_tick;
public ICommand tick_up_cmd =>
_tick_up_cmd ??= new DelegateCommand(() =>
request_tick?.Invoke(true));
public ICommand tick_down_cmd =>
_tick_down_cmd ??= new DelegateCommand(() =>
request_tick?.Invoke(false));
}
}
@@ -0,0 +1,11 @@
#nullable enable
namespace mbts.spark.VolSurface {
using System.Windows.Media;
readonly struct VolSurfaceCellState {
public bool is_dirty => committed_text is not null;
public FormattedText? text { get; init; }
public FormattedText? committed_text { get; init; }
}
}
@@ -0,0 +1,80 @@
#nullable enable
namespace mbts.spark {
using bts;
using mbts.ui.controls;
using mbts.ui.shell;
using Spark.Core;
using System;
class VolSurfaceCellVM : DisposableViewModelBase {
readonly Property<object?> _candidate_value;
readonly Property<object?> _committed_value;
readonly DelegateProperty<bool> _is_dirty;
readonly DeferrableAction _refresh;
public VolSurfaceCellVM(
VolSurfaceDisplayGridExpiration expiration, VolSurfaceDisplayGridColumn column) {
this.column = column ?? throw new ArgumentNullException(nameof(column));
this.expiration = expiration ?? throw new ArgumentNullException(nameof(expiration));
_committed_value = backing<object?>(nameof(committed_value), column.comparer);
_candidate_value = backing<object?>(nameof(candidate_value), column.comparer);
_is_dirty = backing(
nameof(is_dirty), () => !column.comparer.Equals(candidate_value, committed_value));
_refresh = new(_is_dirty.refresh);
_committed_value.Changed += on_committed_changed;
_candidate_value.Changed += on_candidate_changed;
_is_dirty.Changed += (o, n) => {
Log.assert(o != n);
// TODO: John, this was logged too many times
// Log.Ui.info(
// $"VolSurface '{expiration}.{column}' is_dirty changed to {n}. " +
// $"commited: {committed_value}; candidate: {candidate_value}");
};
void on_committed_changed(object? oldval, object? newval) =>
_is_dirty.refresh();
void on_candidate_changed(object? oldval, object? newval) =>
_is_dirty.refresh();
}
public event PropertyChange<object?>? candidate_value_changed {
add => _candidate_value.Changed += value;
remove => _candidate_value.Changed -= value;
}
public VolSurfaceDisplayGridColumn column { get; }
public string column_id => column.unique_col_name;
public VolSurfaceDisplayGridExpiration expiration { get; }
public object? committed_value {
get => _committed_value.Value;
set => _committed_value.set(value);
}
public object? candidate_value {
get => _candidate_value.Value;
set => _candidate_value.set(value);
}
public bool is_dirty => _is_dirty.Value;
public IObservable<object?> observe_candidate(bool start_immediately = false) =>
_candidate_value.observe_current(start_immediately);
public void reset(object? committed_value, object? candidate_value) {
using var _ = _refresh.defer();
this.committed_value = committed_value;
this.candidate_value = candidate_value;
}
public void revert() =>
candidate_value = committed_value;
public override string ToString() =>
$"column: {column}, committed: {committed_value}, candidate: {candidate_value}";
}
}
@@ -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,12 +73,12 @@ 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
});
view.SetBinding(TextBlock.TextProperty, new Binding(nameof(VolGridCellVM.candidate_value)) {
view.SetBinding(TextBlock.TextProperty, new Binding(nameof(VolSurfaceCellVM.candidate_value)) {
Converter = ValueConverter.create(obj => model.format(obj))
});
return view;
@@ -101,16 +101,16 @@ namespace mbts.spark.VolSurface {
view.SetBinding(FrameworkElement.DataContextProperty, new Binding() {
Converter = _data_context_converter
});
view.SetBinding(VolSurfaceCellView.CommittedValueProperty, new Binding(nameof(VolGridCellVM.committed_value)) {
view.SetBinding(VolSurfaceCellView.CommittedValueProperty, new Binding(nameof(VolSurfaceCellVM.committed_value)) {
Mode = BindingMode.OneWay,
Converter = ValueConverter.create(obj => model.format(obj))
});
view.SetBinding(VolSurfaceCellView.CandidateValueProperty, new Binding(nameof(VolGridCellVM.candidate_value)) {
view.SetBinding(VolSurfaceCellView.CandidateValueProperty, new Binding(nameof(VolSurfaceCellVM.candidate_value)) {
Mode = BindingMode.TwoWay,
Converter = ValueConverter.create<object, string>(obj => model.format(obj), obj => model.parse(obj))
});
view.SetBinding(VolSurfaceCellView.TickDownCommandProperty, new Binding(nameof(VolGridTickCellVM.tick_down_cmd)));
view.SetBinding(VolSurfaceCellView.TickUpCommandProperty, new Binding(nameof(VolGridTickCellVM.tick_up_cmd)));
view.SetBinding(VolSurfaceCellView.TickDownCommandProperty, new Binding(nameof(VolSurfaceTickCellVM.tick_down_cmd)));
view.SetBinding(VolSurfaceCellView.TickUpCommandProperty, new Binding(nameof(VolSurfaceTickCellVM.tick_up_cmd)));
var bd = new Border {
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
@@ -1,4 +1,5 @@
namespace mbts.spark.VolSurface {
#nullable enable
namespace mbts.spark.VolSurface {
using bts;
using bts.collections;
using bts.utils;
@@ -11,6 +12,10 @@
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.Core;
using Spark.Core.Disposables;
using Spark.Core.Collections;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -25,17 +30,20 @@
class VolSurfaceGridVM : DisposableViewModelBase {
readonly VolSurfaceVM _parent;
readonly ObservableCollection<VolSurfaceDisplayGridExpiration> _expirations = new();
readonly DeferrableActionWrapper _invalidate_rows;
readonly DeferrableAction _invalidate_rows;
readonly ColumnsModel _columns_model;
ISet<string> _hidden_columns;
ISet<VolSurfaceExpiration> _hidden_expirations;
IDisposable _shift_editor;
ISet<VolSurfaceExpiration>? _hidden_expirations;
IDisposable? _shift_editor;
public VolSurfaceGridVM(VolSurfaceVM vm, VolSurfaceDisplayModel model,
ISet<string> hidden_columns, ISet<VolSurfaceExpiration> hidden_expirations) {
Log.assert(hidden_columns != null);
Log.assert(hidden_expirations != null);
public VolSurfaceGridVM(
VolSurfaceVM vm,
VolSurfaceDisplayModel model,
ISet<string> hidden_columns,
ISet<VolSurfaceExpiration> hidden_expirations) {
Log.notnull(hidden_columns);
Log.notnull(hidden_expirations);
_parent = vm;
this.model = model;
_columns_model = new(create_exp_column_view());
@@ -63,16 +71,31 @@
};
_dispose = Disposable.Create(
ObservableAutoWrapper.connect(_expirations, rows, exp => new VolSurfaceRowContext(this, exp), row => row.Dispose()),
ObservableAutoWrapper.connect(_expirations, rows, row_factory),
ObservableAutoWrapper.connect_item_hooks(rows, connect_row),
sorted_visible_rows.bind(visible_rows),
Disposable.Create(() => {
this.model.on_candidate_grid_change -= _on_grid_updated;
this.model.on_committed_grid_change -= _on_grid_updated;
Disposable.dispose(rows);
rows.DisposeAll(true);
Disposable.dispose(ref _shift_editor);
}),
_columns_model);
VolSurfaceRowVM row_factory(VolSurfaceDisplayGridExpiration exp) =>
new(this, exp);
IDisposable connect_row(VolSurfaceRowVM row) {
row.request_calculate += request_recalc;
return Disposable.Create(() => {
row.request_calculate -= request_recalc;
row.Dispose();
});
void request_recalc() =>
model.set_candidate_grid(current_grid);
}
VolSurfaceColumn create_exp_column_view() {
var filter = new ComboCheckBox();
filter.SetResourceReference(FrameworkElement.StyleProperty, "ExpirationFilterDropDown");
@@ -92,7 +115,7 @@
}
}
public event Action<IEnumerable<VolSurfaceDisplayGridExpiration>> on_selection_changed;
public event Action<IEnumerable<VolSurfaceDisplayGridExpiration>>? on_selection_changed;
public VolSurfaceDisplayGrid current_grid { get; private set; }
public VolSurfaceDisplayGrid committed_grid { get; private set; }
@@ -102,14 +125,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 +141,14 @@
.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 populate_empty_exps_cmd => _parent.populate_empty_exps_cmd;
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());
@@ -141,13 +165,14 @@
rows.select_exp().Except(visible_rows.select_exp());
public void invalidate_rows() =>
_invalidate_rows.execute();
_invalidate_rows.Invoke();
public IDisposable defer_invalidate_rows() =>
_invalidate_rows.defer_execution();
_invalidate_rows.defer();
public VolSurfaceColumn get_column(string id) =>
columns.FirstOrDefault(c => c.id == id) as VolSurfaceColumn;
columns.FirstOrDefault(c => c.id == id) as VolSurfaceColumn ??
throw new InvalidOperationException($"Failed to find column '{id}'");
internal void signal_selection_changed() {
var e = on_selection_changed;
@@ -193,23 +218,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));
@@ -218,7 +243,7 @@
!_hidden_columns.Contains(column.unique_col_name);
void _on_grid_updated() {
using var _ = _invalidate_rows.defer_execution();
using var _ = _invalidate_rows.defer();
var grid_new = model.get_active_grid();
// add/remove columns
var cols_new = grid_new.get_ordered_columns()
@@ -243,7 +268,7 @@
}
current_grid = grid_new;
committed_grid = is_dirty ? model.get_committed_grid() : current_grid;
_invalidate_rows.execute();
_invalidate_rows.Invoke();
}
void _launch_shift_editor(VolSurfaceDisplayGridColumn column, Action<double> commit_shift) {
@@ -299,7 +324,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 +332,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);
}
@@ -317,7 +349,7 @@
model.set_candidate_grid(current_grid);
class ColumnsModel : IDisposable {
IDisposable _dispose;
IDisposable? _dispose;
public ColumnsModel(VolSurfaceColumn row_header_col) {
views_with_header_ro = ObservableAutoWrapper.create_read_only_wrapper(views_with_header);
@@ -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,220 @@
#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 Spark.Core.Disposables;
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 populate_empty_exps_cmd => _parent.populate_empty_exps_cmd;
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,149 @@
#nullable enable
namespace mbts.spark.VolSurface {
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.shell;
using Spark.Core;
using Spark.Core.Disposables;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
class VolSurfaceRowVM : DisposableViewModelBase, ISelectable, IFormatCellsToClipboard, DIYGrid.IRowVM {
readonly VolSurfaceGridVM _parent;
readonly VolSurfaceDisplayGridExpiration _exp;
readonly Dictionary<string, CellData> _cells = new();
readonly DeferrableAction _request_calculate;
VolSurfaceRowContextMenuVM? _context_menu;
bool _is_selected;
public VolSurfaceRowVM(VolSurfaceGridVM parent, VolSurfaceDisplayGridExpiration exp) {
_parent = parent;
_exp = exp;
_request_calculate = new(() => request_calculate?.Invoke());
_dispose = Disposable.Create(() => {
_cells.Values.DisposeAll();
_cells.Clear();
_context_menu?.Dispose();
});
}
public event Action<bool>? is_selected_changed;
public event Action? invalidated;
public event Action? request_calculate;
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 VolSurfaceCellVM get_cell(VolSurfaceDisplayGridColumn column) =>
_cells.GetOrAdd(column.unique_col_name, _ => _create_cell(column)).vm;
public void invalidate() {
using (_request_calculate.supress()) {
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 VolSurfaceCellVM(_exp, column)
};
_sync_cell(cell);
return new(cell, _connect_cell(cell));
VolSurfaceCellVM create_tick_cell() {
var cell = new VolSurfaceTickCellVM(_exp, column);
cell.request_tick += is_up => {
var col = _parent.get_column(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(VolSurfaceCellVM cell) {
if (cell is null) {
return;
}
using var _ = _request_calculate.supress();
cell.reset(
committed_value: _parent.committed_grid.read(_exp, cell.column_id),
candidate_value: _parent.current_grid.read(_exp, cell.column_id));
}
IDisposable? _connect_cell(VolSurfaceCellVM cell) {
return cell.column.type switch {
VolSurfaceColumnType.ReadWriteTick => connect_input(),
_ => null
};
IDisposable connect_input() {
cell.candidate_value_changed += on_candidate_value_changed;
return Disposable.Create(() =>
cell.candidate_value_changed -= on_candidate_value_changed);
void on_candidate_value_changed(object? oldval, object? newval) {
var curr = _parent.current_grid.read(expiration, cell.column);
if (cell.column.comparer.Equals(newval, curr)) {
return;
}
var grid = _parent.current_grid;
grid.write(expiration, cell.column, newval);
_request_calculate.Invoke();
}
}
}
class CellData : IDisposable {
IDisposable? _dispose;
public CellData(VolSurfaceCellVM vm, IDisposable? dispose) {
this.vm = vm;
_dispose = Disposable.Create(vm, dispose);
}
public VolSurfaceCellVM vm { get; }
public void Dispose() =>
Disposable.dispose(ref _dispose);
}
}
}
@@ -0,0 +1,27 @@
#nullable enable
namespace mbts.spark {
using mbts.ui;
using mbts.ui.controls;
using System;
using System.Windows.Input;
class VolSurfaceTickCellVM : VolSurfaceCellVM {
ICommand? _tick_up_cmd;
ICommand? _tick_down_cmd;
public VolSurfaceTickCellVM(
VolSurfaceDisplayGridExpiration expiration, VolSurfaceDisplayGridColumn column)
: base(expiration, column) { }
public event Action<bool>? request_tick;
public ICommand tick_up_cmd =>
_tick_up_cmd ??= new DelegateCommand(() =>
request_tick?.Invoke(true));
public ICommand tick_down_cmd =>
_tick_down_cmd ??= new DelegateCommand(() =>
request_tick?.Invoke(false));
}
}
@@ -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;
@@ -96,7 +96,7 @@ namespace mbts.spark {
get => _core_settings.font_weight_override;
set {
using var _ = detect_property_change();
_core_settings.with(font_weight_override: value.HasValue ? new NullableFontWeightProto(value) : null);
_core_settings.with(font_weight_override: value.HasValue ? new(value) : null);
}
}
@@ -1,72 +0,0 @@
using mbts.ui;
using mbts.ui.controls.graph;
using System;
using System.Windows.Input;
using System.Windows.Media;
namespace mbts.spark
{
class VolSurfaceGraphSettingsEditorVM
{
public VolSurfaceGraphSettingsEditorVM(string vol_surface_name, VolSurfaceGraphSettings settings, Action<VolSurfaceGraphSettings> commit) {
this.vol_surface_name = vol_surface_name;
_settings = settings;
this.commit = new DelegateCommand(() => commit(_settings));
}
private readonly VolSurfaceGraphSettings _settings;
public string vol_surface_name { get; private set; }
public VolSurfaceScatterSeriesSettingsVM implied_puts { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.implied_puts); } }
public VolSurfaceScatterSeriesSettingsVM implied_atm { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.implied_atm); } }
public VolSurfaceScatterSeriesSettingsVM implied_calls { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.implied_calls); } }
public VolSurfaceScatterSeriesSettingsVM put_control_points { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.put_control_points); } }
public VolSurfaceScatterSeriesSettingsVM atm { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.atm); } }
public VolSurfaceScatterSeriesSettingsVM call_control_points { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.call_control_points); } }
public VolSurfaceLineSeriesSettingsVM put_wing { get { return new VolSurfaceLineSeriesSettingsVM(_settings.put_wing); } }
public VolSurfaceLineSeriesSettingsVM inner_curve { get { return new VolSurfaceLineSeriesSettingsVM(_settings.inner_curve); } }
public VolSurfaceLineSeriesSettingsVM call_wing { get { return new VolSurfaceLineSeriesSettingsVM(_settings.call_wing); } }
public VolSurfaceLineSeriesSettingsVM vol_path { get { return new VolSurfaceLineSeriesSettingsVM(_settings.vol_path); } }
public ICommand commit { get; private set; }
}
class VolSurfaceScatterSeriesSettingsVM
{
public VolSurfaceScatterSeriesSettingsVM(ScatterSeriesSettings settings) {
_settings = settings;
}
private readonly ScatterSeriesSettings _settings;
public MarkerShape shape { get { return _settings.shape; } set { _settings.shape = value; } }
public double size { get { return _settings.size; } set { _settings.size = value; } }
public Color fill {
get => _settings.fill;
set => _settings.fill = value;
}
public Color stroke {
get => _settings.stroke;
set => _settings.stroke = value;
}
public Array shapes { get { return Enum.GetValues(typeof(MarkerShape)); } }
}
class VolSurfaceLineSeriesSettingsVM
{
public VolSurfaceLineSeriesSettingsVM(LineSeriesSettings settings) {
_settings = settings;
}
private readonly LineSeriesSettings _settings;
public Color color { get { return (Color)_settings.color; } set { _settings.color = (BTSColor)value; } }
public double thickness { get { return _settings.stroke_thickness; } set { _settings.stroke_thickness = value; } }
}
}
@@ -9,6 +9,9 @@ namespace mbts.spark {
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.Core.Disposables;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
@@ -23,6 +26,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 +119,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 +375,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();
@@ -518,17 +540,22 @@ namespace mbts.spark {
public ObservableCollection<VSSymbol> symbols { get; private set; }
public void Dispose() =>
Disposable.dispose(symbols);
symbols.DisposeAll(true);
}
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(
bus.subscribe(SparkTags.ExpirationParametersInputTag).OnDispatcher().Subscribe(on_exp_params_input)) +
new Action(() => Disposable.dispose(driver_grids));
_dispose = Disposable.Create(
driver_grids.Subscribe((s, e) =>
selected_driver_grid ??= driver_grids.FirstOrDefault()),
bus.subscribe(SparkTags.ExpirationParametersInputTag).OnDispatcher().Subscribe(on_exp_params_input),
Disposable.Create(() => driver_grids.DisposeAll(true)));
void on_exp_params_input(AnalyticsExpirationParametersMap data) {
var driver_map = data.get_option_driver_map();
@@ -586,6 +613,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;
+132 -96
View File
@@ -1,5 +1,5 @@
#nullable enable
namespace mbts.spark {
using bts;
using bts.api;
using bts.collections;
@@ -8,48 +8,107 @@ namespace mbts.spark {
using mbts.spark.VolSurface;
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.settings;
using mbts.ui.shell;
using Spark.Core.Disposables;
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
populate_empty_exps_cmd = new Command(() => { _model.populate_empty_expirations(); });
_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 +128,72 @@ 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 populate_empty_exps_cmd { get; }
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 +207,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;
}
}
Loaded 100 of 1815 files, more files were not shown because too many files have changed in this diff. Show more