Compare commits

..
76 Commits
Author SHA1 Message Date
John Colvin 709334a1aa test 2023-07-07 17:47:07 -04:00
John Colvin f9a6e0963c chore: Remove Spark.Admin.WebApp
These files were added by accident (leftover from switching branches
from development -> spark_crypto.prod)
2023-07-06 14:52:57 +00:00
John Colvin b2879837c6 chore: Remove devcontainer.json 2023-07-06 12:26:48 +00:00
John Colvin 0d03ddb009 Merge remote-tracking branch 'origin/spark_crypto.prod' into spark_crypto.tick_hotfix 2023-07-06 12:26:28 +00:00
John Colvin a6dfa4ae80 fix: Don't show decimal BTC Futs/Spd qtys
They tick in multiples of 10, so decimal precision isn't needed
2023-07-05 18:20:53 -04:00
John Colvin e66ec82ba8 hotfix: Setup default cfg for new Deribit price ticks 2023-07-05 18:19:49 -04:00
John Colvin 9ce5e971c6 fix: Fix typos in BTSColor paths in xaml 2023-07-05 18:11:40 -04:00
John Colvin 3e7cc49ebb hotfix: Format text w/ RegionalTickFactors in PriceEntryControl 2023-07-05 18:11:40 -04:00
John Colvin d07e68b6e2 hotfix: Use 1st leg's min price tick rule for Deribit combos 2023-07-05 18:11:40 -04:00
John Colvin 619ece2313 refactor: Consolidate impl for 'round_to_tick' overloads
Also add a 'decimal' overload for RegionalTickFactors. This is more work
for Deribit tick hotfix.
2023-07-05 18:11:40 -04:00
John Colvin 1dda9566f3 hotfix: Use '.' separator if tick unit is multiple of base 2023-07-05 18:11:06 -04:00
John Colvin a524ca02a5 refactor: Change tick arithmetic to use int64
The tick count is "price / tick_size" and tick_size is usually < 1, so
the extra bits may be needed to avoid arithmetic overflow
2023-07-05 12:02:28 -04:00
John Colvin 3c97f2552b fix build: Don't use libfmt or ranges in win cpp
I can't deal with this anymore. My build is suddenly broken on Windows
(for spark_crypto.prod branch). I assume they updated the compiler
in a way that isn't backwards compatible. Thanks Windows.
2023-07-05 11:58:14 -04:00
John Colvin 15b1d55ef1 fix build: Disable Binance md code on win 2023-07-05 11:58:14 -04:00
John Colvin 4e42c9f01b test: Refactor tick tests for RegionalTickFactors
Gives us some peace of mind about the dynamic ticks hotfix for Deribit
2023-07-05 11:58:14 -04:00
John Colvin 76775f821a hotfix: Support dynamic ticks in order ticket 2023-07-05 11:58:14 -04:00
John Colvin e7088f6b1c hotfix: Support dynamic ticks in ladder
Deribit now provides dynamic price ticks (a list of ticks per range).

https://www.deribit.com/kb/4-july-2023
https://www.deribit.com/kb/deribit-on-screen-options-tick-size-reduction
2023-07-05 11:58:14 -04:00
Taha 1fb42ade59 Adding perf logs on the front end 2023-07-05 10:50:13 -04:00
Taha 129650e9d4 Only the skew owner publishes theos to the server 2023-07-05 10:50:13 -04:00
John Colvin 170a44ac04 fix: Check sign to tick in correct direction
Don't assume it's positive and blindly tickup
2023-07-03 22:34:46 -05:00
Taha Afzal 7e04f02327 Merge branch 'spark_crypto.prod.autofit' into spark_crypto.prod 2023-07-04 03:21:28 +00:00
Taha Afzal abda2dbf97 VolSurfaces and achived theo history size is not mantained at runtime 2023-07-04 03:13:46 +00:00
Taha Afzal ad1a45cf49 ArchivedTheos are truncated on a server start 2023-07-04 03:13:46 +00:00
John Colvin e9abdd0ff2 chore: Remove unused fn 'gen_prices' 2023-07-03 12:30:03 -05:00
John Colvin 9254002318 fix: Check HasPrice/QuantityDisplay before accessing prop 2023-07-03 12:24:20 -05:00
John Colvin 596780b7f4 chore: Remove unused 'unit_quantity' prop 2023-07-03 12:22:37 -05:00
John Colvin 7ba061ac20 hotfix: Add cfg to account for new deribit tick format 2023-07-02 16:58:53 -05:00
John Colvin c01593d119 fix (ui colors): Cherry-pick synth editor dark theme from dev 2023-06-26 12:26:38 -04:00
Taha 09e2a1764f Only the user with control over the volsurface can save it 2023-06-15 11:44:34 -04:00
John Colvin a780668bce fix: Ensure tick up/down values are within min/max bounds 2023-06-15 11:43:58 -04:00
John Colvin 5b79aeaa14 ui: Enforce min auto-fit period (30 secs) 2023-06-15 11:37:18 -04:00
John Colvin 049c006b5f ui: Disable driver/atm pts moved auto-fit ui 2023-06-15 11:37:18 -04:00
John Colvin 6fdc344472 feat: Add 'acquire ownership' button to vs context menu 2023-06-15 11:37:18 -04:00
John Colvin cb09b93553 chore: Rename ns bts.reactive -> Spark.Core.Reactive 2023-06-15 11:37:18 -04:00
John Colvin 21447d32e5 fix (vs ui): Only log 'is_dirty' changes for editable cols 2023-06-15 11:37:18 -04:00
Taha 28b03e1cd2 Only the user with control over the volsurface can save it 2023-06-14 22:23:45 -04:00
Taha a7acb89c15 Fixing merge conflict 2023-06-14 15:57:42 -04:00
John Colvin 35289710ba fix: Ensure tick up/down values are within min/max bounds 2023-06-14 14:20:47 -04:00
Taha 4677acfb39 Merge branch 'spark_crypto.prod.autofit' of bitbucket.org:bluetradesys/spark into spark_crypto.prod.autofit 2023-06-14 13:55:03 -04:00
Taha ac05d0d69e AutoFitter reads the settings from the settings now 2023-06-14 13:54:53 -04:00
John Colvin 25a9b6b433 fix: Ensure tick up/down values are within min/max bounds 2023-06-14 13:49:49 -04:00
John Colvin b78713ad0d ui: Enforce min auto-fit period (30 secs) 2023-06-14 12:59:40 -04:00
John Colvin 1f3d0e879c ui: Disable driver/atm pts moved auto-fit ui 2023-06-14 12:59:39 -04:00
John Colvin baad4dc68e feat: Add 'acquire ownership' button to vs context menu 2023-06-14 12:22:57 -04:00
John Colvin ef7c0c7a30 chore: Rename ns bts.reactive -> Spark.Core.Reactive 2023-06-14 11:39:06 -04:00
Taha 3b3c4a2a35 Merge branch 'spark_crypto.prod.autofit' of bitbucket.org:bluetradesys/spark into spark_crypto.prod.autofit 2023-06-14 10:21:55 -04:00
John Colvin ef9fc66a31 fix (vs ui): Only log 'is_dirty' changes for editable cols 2023-06-14 09:44:42 -04:00
John Colvin 212d9c853b fix: Init auto fit vals in vs settings editor 2023-06-14 09:09:34 -04:00
Taha 7815b18b6b Merge branch 'spark_crypto.prod.autofit' of bitbucket.org:bluetradesys/spark into spark_crypto.prod.autofit 2023-06-13 22:34:12 -04:00
Taha 05126074d4 Enabling AutoFit 2023-06-13 22:34:07 -04:00
John Colvin 3611d2c1f3 fix: Enable tick up/down buttons for nullable uint32 ctrl 2023-06-13 15:43:33 -04:00
John Colvin b5ad4b8104 feat: Add auto-fit ui for vs settings 2023-06-13 15:43:33 -04:00
Taha 43d7c0a2b5 Comments 2023-06-12 13:43:42 -04:00
Taha 12e361cec7 AutoFit based on a timer works now 2023-06-11 21:59:46 -04:00
John Colvin 82c126362d fix build: Fix a few path errors in publish target 2023-05-31 22:13:52 -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
215 changed files with 9249 additions and 7234 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"
]
}
}
}
+55 -53
View File
@@ -1,53 +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>
<EnablePreviewFeatures>true</EnablePreviewFeatures>
</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>
@@ -3,7 +3,6 @@ namespace mbts.spark {
using bts.api;
using bts.api.analytics;
using bts.collections;
using bts.reactive;
using bts.utils;
using mbts;
@@ -18,6 +17,7 @@ namespace mbts.spark {
using Spark.Core;
using Spark.Core.Collections;
using Spark.Core.Disposables;
using Spark.Core.Reactive;
using Spark.ViewModel.Commands;
using System;
@@ -43,6 +43,7 @@ namespace mbts.spark {
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;
(ICommand cmd, IDisposable can_exe_sub)? _smart_copy_roll_target_to_selection_cmd;
@@ -65,9 +66,7 @@ namespace mbts.spark {
_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;
}
@@ -297,8 +296,8 @@ namespace mbts.spark {
symbols.sync_with(_parameters.Select(p => p.security.symbol).Distinct().Ordered());
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;
}
}
@@ -0,0 +1,120 @@
namespace mbts.spark {
using bts;
using bts.api;
using mbts;
using mbts.analytics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
// For each vs, it sends the vol surface calc request (_do_periodic_auto_fit)
// and then commits the response
public class SingleVolSurfaceAutoFitSource : IDisposable {
private readonly ThreadedBlackboard _bb;
private readonly int _vs_id;
private readonly ITag<VolSurfaceInput> _vs_input_tag;
private readonly ITag<VolSurfaceCalculationResponse> _vs_calc_response_tag;
private DateTime _last_req_time = DateTime.MinValue;
private TimeSpan _req_period = TimeSpan.MaxValue;
private int _req_id = 0;
public SingleVolSurfaceAutoFitSource(int vs_id, ThreadedBlackboard bb) {
_bb = bb;
_vs_id = vs_id;
_vs_input_tag = SparkTags.VolSurfaceCommittedInputTag(vs_id);
_vs_calc_response_tag = SparkTags.VolSurfaceAutoCalculationResponseTag(vs_id);
_bb.subscribe(_vs_input_tag);
_bb.subscribe(_vs_calc_response_tag);
_bb.subscribe(SparkTags.CurrentUser);
_bb.data_callback += _on_bb_data;
_bb.timer_callback += _on_bb_timer;
}
private void _on_bb_data(object tag, object data) {
if (tag.Equals(_vs_input_tag))
_possibly_autofit();
else if (tag.Equals(_vs_calc_response_tag)) {
VolSurfaceCalculationResponse calc_resp = data as VolSurfaceCalculationResponse;
bts.Log.Gen.info($"SingleVolSurfaceAutoFitSource._on_bb_data vs_id: {_vs_id} " +
$"received calculation response");
_bb.post(SparkTags.VolSurfaceCommitTag(_vs_id),
calc_resp.volsurface_calculation_output.volsurface_input);
}
}
private bool _user_has_vs_control() {
VolSurfaceInput vs_input = _bb.read_state(_vs_input_tag);
string current_user = _bb.read_state(SparkTags.CurrentUser).name;
return vs_input != null &&
vs_input.surface_settings.core_settings.vs_manager == current_user;
}
private void _on_bb_timer() {
_possibly_autofit();
}
private void _possibly_autofit() {
var auto_fit_period = _get_auto_fit_periodic();
if (!auto_fit_period.HasValue)
return;
if (DateTime.Now - _last_req_time <= auto_fit_period)
return;
if (!_user_has_vs_control())
return;
// auto fit here
bts.Log.Gen.info($"SingleVolSurfaceAutoFitSource vs_id: {_vs_id} requesting fit " +
$"last_req_time: {_last_req_time} period: {auto_fit_period.Value}");
_send_request();
}
private Nullable<TimeSpan> _get_auto_fit_periodic() {
VolSurfaceInput vs_input = _bb.read_state(_vs_input_tag);
if (vs_input == null)
return null;
var fit_settings =
VolSurfaceDataFunctions.get_market_fit_settings(vs_input.surface_settings);
if (fit_settings == null)
return null;
var auto_fit_setting = fit_settings.vs_auto_fit_settings;
if (auto_fit_setting == null)
return null;
if (auto_fit_setting.auto_fit_region == VolSurfaceEnums.VolCurveFitRegion.None)
return null;
var time_based_fit_setting = auto_fit_setting.time_based_settings;
if (time_based_fit_setting == null)
return null;
if (!time_based_fit_setting.period_seconds.HasValue)
return null;
return TimeSpan.FromSeconds(time_based_fit_setting.period_seconds.Value);
}
private void _send_request() {
VolSurfaceInput vs_input = _bb.read_state(_vs_input_tag);
if (vs_input == null)
return;
VolCurveMarketFitAction mf_action = new VolCurveMarketFitAction(
VolCurveMarketFitAction.ActionType.FitWholeCurve, null, false);
VolCurveAction vc_action = new VolCurveAction(mf_action);
IDictionary<VolSurfaceExpiration, VolCurveAction> action_map =
vs_input.surface_parameters.curve_parameters_map.ToDictionary(
i => i.Item1,
i => vc_action
);
VolSurfaceCalculationRequest req = new VolSurfaceCalculationRequest(vs_input,
_req_id++, action_map, true, true);
_last_req_time = DateTime.Now;
_bb.post(SparkTags.VolSurfaceAutoCalculationRequestTag(_vs_id), req);
}
#region IDisposable
public void Dispose() {
_bb.data_callback -= _on_bb_data;
_bb.timer_callback -= _on_bb_timer;
}
#endregion
}
}
@@ -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);
}
@@ -4,6 +4,7 @@
using bts.api.analytics;
using mbts.analytics;
using mbts.ui;
using Spark.Core.Protobuf;
@@ -13,6 +14,7 @@
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
using System.Windows;
// For a single VolSurface this class
// 1. Listents to commmits and calls the service to persist data
@@ -24,7 +26,6 @@
private readonly ITag<VolSurfaceInput> _in_bb_committ_tag;
private readonly AnalyticsService _analytics_service;
private readonly HighPerformanceTimer _timer = new HighPerformanceTimer();
private readonly string _user;
private readonly List<IDisposable> _disposables = new List<IDisposable>();
private IDictionary<UInt64, VolSurfaceInputSnapshot> _snp_shot_map = new
Dictionary<UInt64, VolSurfaceInputSnapshot>();
@@ -35,10 +36,10 @@
volsurface_id));
_volsurface_id = volsurface_id;
_bb = threaded_bb;
_user = "TEST_USER"; // TODO
_in_bb_committ_tag = SparkTags.VolSurfaceCommitTag(volsurface_id);
_analytics_service = analytics_service;
_bb.subscribe(_in_bb_committ_tag);
_bb.subscribe(SparkTags.CurrentUser);
_bb.data_callback += _on_bb_data;
var vs_sub = _analytics_service.subscribei_volsurfaces()
.ObserveOn(SynchronizationContext.Current)
@@ -54,8 +55,10 @@
private void _on_vss(bts.api.core.Update<VolSurfaceEntryImmutable, UInt64> update) {
IEnumerable<VolSurfaceEntryImmutable> all_vss = update.all;
var this_vs_vss = all_vss.Where(vs => vs.VsId == _volsurface_id);
bts.Log.Gen.info(String.Format("SingleVolSurfaceGateway._on_vss count:{0} vs_count:{1}",
all_vss.Count(), this_vs_vss.Count()));
bts.Log.Gen.info(
$"SingleVolSurfaceGateway._on_vss vs_count: {this_vs_vss.Count()} " +
$"all: {update.all.Count()} added: {update.added.Count()} " +
$"updated: {update.changed.Count()} removed: {update.removed.Count()}");
if (this_vs_vss.Count() == 0) {
return;
}
@@ -83,22 +86,39 @@
static VolSurfaceInput _to_vs_input(VolSurfaceEntryImmutable vs) =>
ProtobufSerializationHelper.deserialize<VolSurfaceInput>(vs.Volsurface.ToByteArray());
// private void _show_save_error(string message) {
// BTSMessageBox.Show(message, "Vol Save Error", BTSMessageBoxButtons.OK);
// }
private void _on_bb_data(object tag, object data) {
if (_in_bb_committ_tag.Equals(tag)) {
try {
_timer.start();
VolSurfaceInput vs_input = data as VolSurfaceInput;
var user_tup = _bb.read_state(SparkTags.CurrentUser);
string current_user = user_tup.name;
string vs_manager = vs_input.surface_settings.core_settings.vs_manager;
if (current_user != vs_manager) {
string msg = $"User {current_user} does not have the permission to save vols. " +
$"Permission can be obtained via the grid context menu item 'Acquire ownership from {vs_manager}'";
BTSMessageBox.Show(msg, "Vol Save Error", BTSMessageBoxButtons.OK);
return;
}
_sanitize_input(ref vs_input);
vs_input = VolSurfaceDataFunctions.unset_driver_overrides(vs_input);
vs_input.saver_login = _user;
VolSurfaceUtilityFunctions.save_volsurface(vs_input, _analytics_service, _user);
VolSurfaceUtilityFunctions.save_volsurface(vs_input, _analytics_service, current_user);
_timer.stop();
Log.Gen.info(String.Format(
"SingleVolSurfaceGateway._on_bb_data Time to commit volsurface {0} {1} msecs",
_volsurface_id, _timer.lastIntervalTime));
var archived_theos = _get_theos();
if (archived_theos != null)
if (archived_theos != null) {
_timer.start();
_analytics_service.archive_theos(archived_theos);
_timer.stop();
Log.Gen.info($"SingleVolSurfaceGateway._on_bb_data archiving theos size: " +
$"{archived_theos.SecTheo.Count} time: {_timer.lastIntervalTime} msecs");
}
} catch (Exception ex) {
Log.Gen.warn(ex.ToString());
_bb.post(SparkTags.MessageDisplayTag,
@@ -36,7 +36,11 @@ namespace mbts.spark {
new SingleVolSurfaceDataSource(SingleVolSurfaceDataSource.SymbolListType.Committed, _vs_id, _bb,
a_syms => new SingleVolSurfaceCommittedOutputRetriever(_vs_id, _bb, a_syms)),
new SingleVolSurfaceDataSource(SingleVolSurfaceDataSource.SymbolListType.Combined, _vs_id, _bb,
a_syms => new SingleVolSurfaceRequestCalculator(_vs_id, a_syms, _bb)),
a_syms => new SingleVolSurfaceRequestCalculator(
SingleVolSurfaceRequestCalculator.RequestType.UI, _vs_id, a_syms, _bb)),
new SingleVolSurfaceDataSource(SingleVolSurfaceDataSource.SymbolListType.Combined, _vs_id, _bb,
a_syms => new SingleVolSurfaceRequestCalculator(
SingleVolSurfaceRequestCalculator.RequestType.AUTO, _vs_id, a_syms, _bb)),
new SingleVolSurfaceMarketImpliedVolSource(_vs_id, _bb),
// new SingleVolSurfaceTheoSource(_vs_id, _bb),
// TODO: suspending heatmaps for now (12/24/21)
@@ -44,6 +48,7 @@ namespace mbts.spark {
// server work that can optionally be done on the client
new SingleVolSurfaceDataSource (SingleVolSurfaceDataSource.SymbolListType.Committed, _vs_id, _bb,
a_syms => new SingleVolSurfaceInterpGreeksPublisher (_vs_id, _bb, a_syms)),
new SingleVolSurfaceAutoFitSource(_vs_id, _bb),
};
}
@@ -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(
@@ -18,10 +18,16 @@ namespace mbts.spark {
// Pubs :
// 1. Calc Resp
public class SingleVolSurfaceRequestCalculator : IDisposable {
public enum RequestType {
UI = 0,
AUTO
}
private readonly RequestType _request_type = RequestType.UI;
private readonly int _vs_id;
private readonly HashSet<string> _symbols;
private readonly ThreadedBlackboard _bb;
private readonly ITag<VolSurfaceCalculationRequest> _in_bb_request_tag;
private readonly ITag<VolSurfaceCalculationRequest> _in_bb_auto_request_tag;
private readonly ITag<VolSurfaceNonVolData> _in_bb_nonvol_data_tag;
private readonly ITag<VolSurfaceStandardTime> _in_bb_vs_standard_time_tag;
private readonly ITag<VolSurfaceEnums.MarketSide> _in_bb_market_impliedvol_side_tag;
@@ -30,18 +36,22 @@ namespace mbts.spark {
/// data
private VolSurfaceOutput _last_output;
public SingleVolSurfaceRequestCalculator(int vs_id, IEnumerable<string> symbols,
public SingleVolSurfaceRequestCalculator(RequestType request_type,
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} request_type: {request_type}");
_request_type = request_type;
_vs_id = vs_id;
_symbols = new HashSet<string>(symbols);
_bb = threaded_bb;
_in_bb_request_tag = SparkTags.VolSurfaceCalculationRequestTag(vs_id);
_in_bb_auto_request_tag = SparkTags.VolSurfaceAutoCalculationRequestTag(vs_id);
_in_bb_nonvol_data_tag = SparkTags.VolSurfaceNonVolDataTag(vs_id);
_in_bb_vs_standard_time_tag = SparkTags.VolSurfaceStandardTimeTag(vs_id);
_in_bb_market_impliedvol_side_tag = SparkTags.VolSurfaceMarketImpliedVolSide(vs_id);
_in_bb_dirty_tag = SparkTags.VolSurfaceDirtyStateTag(vs_id);
_bb.subscribe(_in_bb_request_tag);
_bb.subscribe(_in_bb_auto_request_tag);
_bb.subscribe(_in_bb_nonvol_data_tag);
_bb.subscribe(_in_bb_vs_standard_time_tag);
_bb.subscribe(_in_bb_vs_standard_time_tag);
@@ -51,11 +61,21 @@ namespace mbts.spark {
}
private void _on_bb_data(object tag, object data) {
if (_in_bb_request_tag.Equals(tag) || _in_bb_dirty_tag.Equals(tag))
_recompute_and_publish(true);
else if (_in_bb_nonvol_data_tag.Equals(tag) || _in_bb_vs_standard_time_tag.Equals(tag))
_recompute_and_publish(false);
switch (_request_type) {
case RequestType.UI: {
if (_in_bb_request_tag.Equals(tag) || _in_bb_dirty_tag.Equals(tag))
_recompute_and_publish(true);
else if (_in_bb_nonvol_data_tag.Equals(tag) || _in_bb_vs_standard_time_tag.Equals(tag))
_recompute_and_publish(false);
break;
}
case RequestType.AUTO: {
if (tag.Equals(_in_bb_auto_request_tag)) {
_serve_auto_request();
}
break;
}
}
}
private void _recompute_and_publish(bool is_new_request) {
@@ -80,7 +100,7 @@ namespace mbts.spark {
nonvol_data.driver_price_map,
vs_standard_time, true);
IDictionary<VolSurfaceExpiration, VolCurveAction> action_map =
_post_process_action(effective_req, aux_data_map);
_post_process_action(_bb, _vs_id, effective_req, aux_data_map);
_last_output = GeneralVolSurfaceCalculator.compute(effective_req.volsurface_input,
nonvol_data.contracts,
aux_data_map,
@@ -89,16 +109,49 @@ namespace mbts.spark {
effective_req.cascade_up,
effective_req.cascade_down);
_timer.stop();
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._recompute_and_publish time: " +
$"{_timer.lastIntervalTime}");
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._recompute_and_publish vs_id: {_vs_id} " +
$"time: {_timer.lastIntervalTime}");
_bb.post(SparkTags.VolSurfaceCalculationResponseTag(_vs_id),
new VolSurfaceCalculationResponse(_last_output, effective_req.request_id));
}
}
}
private void _serve_auto_request() {
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._serve_auto_request " +
$"vs_id: {_vs_id} auto request received");
bool is_dirty = _bb.read_state(_in_bb_dirty_tag, false);
VolSurfaceNonVolData nonvol_data = _bb.read_state(_in_bb_nonvol_data_tag);
VolSurfaceStandardTime vs_standard_time = _bb.read_state(_in_bb_vs_standard_time_tag);
VolSurfaceCalculationRequest auto_req = _bb.read_state(_in_bb_auto_request_tag);
if (is_dirty || nonvol_data == null || vs_standard_time == null || auto_req == null) {
return;
}
_timer.start();
IDictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData> aux_data_map =
VolSurfaceUtilityFunctions.compute_aux_data(auto_req.volsurface_input,
nonvol_data.input,
nonvol_data.driver_price_map,
vs_standard_time, true);
IDictionary<VolSurfaceExpiration, VolCurveAction> action_map =
_post_process_action(_bb, _vs_id, auto_req, aux_data_map);
var vs_output = GeneralVolSurfaceCalculator.compute(auto_req.volsurface_input,
nonvol_data.contracts,
aux_data_map,
action_map,
null,
auto_req.cascade_up,
auto_req.cascade_down);
_timer.stop();
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._serve_auto_request vs_id: {_vs_id} " +
$"time: {_timer.lastIntervalTime}");
_bb.post(SparkTags.VolSurfaceAutoCalculationResponseTag(_vs_id),
new VolSurfaceCalculationResponse(vs_output, auto_req.request_id));
}
/// Computes the impl vol if the action is fit to market
private IDictionary<VolSurfaceExpiration, VolCurveAction> _post_process_action(
private static IDictionary<VolSurfaceExpiration, VolCurveAction> _post_process_action(
ThreadedBlackboard bb, int vs_id,
VolSurfaceCalculationRequest req,
IDictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData> aux_data_map) {
IDictionary<VolSurfaceExpiration, VolCurveAction> rv = req.action_map;
@@ -109,7 +162,7 @@ namespace mbts.spark {
VolCurveAction rep_action = rv.ElementAt(0).Value;
if (rep_action.action_type == VolCurveAction.ActionType.FitToMarket) {
IDictionary<VolSurfaceExpiration, VolCurveMarketImpliedVolData> impl_vol_map =
_fill_in_implied_vols(req.volsurface_input, req.action_map, aux_data_map,
_fill_in_implied_vols(bb, vs_id, req.volsurface_input, req.action_map, aux_data_map,
req.cascade_up, req.cascade_down);
rv = impl_vol_map.ToDictionary(kv => kv.Key, kv => new VolCurveAction(
new VolCurveMarketFitAction(rep_action.market_fit_action.fit_action, kv.Value,
@@ -119,7 +172,8 @@ namespace mbts.spark {
return rv;
}
private IDictionary<VolSurfaceExpiration, VolCurveMarketImpliedVolData> _fill_in_implied_vols(
private static IDictionary<VolSurfaceExpiration, VolCurveMarketImpliedVolData> _fill_in_implied_vols(
ThreadedBlackboard bb, int vs_id,
VolSurfaceInput vs_inp,
IDictionary<VolSurfaceExpiration, VolCurveAction> action_map,
IDictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData> aux_data_map,
@@ -140,15 +194,15 @@ namespace mbts.spark {
applicable_exps = applicable_exps.Where(vs_exp => master_exps.Contains(vs_exp));
VolSurfaceEnums.MarketSide impliedvol_side =
SingleVolSurfaceMarketImpliedVolSource._get_market_impliedvol_side(_bb, _vs_id);
SingleVolSurfaceMarketImpliedVolSource._get_market_impliedvol_side(bb, vs_id);
foreach (VolSurfaceExpiration vs_exp in applicable_exps) {
VolSurfaceExpiration md_exp;
VolCurveMarketImpliedVolData exp_impl_data =
VolSurfaceCoreFunctions.compute_implied_vols(vs_inp, vs_exp, aux_data_map,
arg_vs_exp => SingleVolSurfaceMarketImpliedVolSource.get_option_bbo(_bb, arg_vs_exp),
arg_vs_exp => SingleVolSurfaceMarketImpliedVolSource.get_option_bbo(bb, arg_vs_exp),
impliedvol_side,
SingleVolSurfaceMarketImpliedVolSource._ignore_market_implied_vol_source_settings(
_bb, _vs_id),
bb, vs_id),
out md_exp);
rv[vs_exp] = exp_impl_data;
}
@@ -81,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);
}
@@ -270,6 +270,7 @@ namespace mbts.spark {
new mbts.analytics.VolSurfaceNonVolInput(exp_param_map.exp_map.ToDictionary()));
} else if (_in_bb_req_vol.Equals(tag)) {
ClientArchivedVolRequest client_req = _bb.read_state(_in_bb_req_vol);
bts.Log.Ui.info($"VolSurfaceBusManager._on_bb_update ClientArchivedVolRequest: {client_req.ToString()}");
ArchivedTheoRetrieval ret = client_req.ret;
if (ret == null || ret.SecTup == null) {
bts.Log.Ui.warn($"VolSurfaceBusManager malformed ArchivedTheoRetrieval");
@@ -5,6 +5,7 @@ using bts.api;
using bts.collections;
using System.Linq;
using bts.api.orderman;
using bts.api.analytics;
using bts;
namespace mbts.spark {
@@ -23,6 +24,8 @@ namespace mbts.spark {
_order_service = order_service;
_bb.subscribe(SparkTags.AllInterpGreeks);
_bb.subscribe(SparkTags.SystemContractsTag);
_bb.subscribe(SparkTags.CurrentUser);
_bb.subscribe(SparkTags.VolSurfaceUsageTag);
_bb.data_callback += _on_data;
}
@@ -55,10 +58,32 @@ namespace mbts.spark {
return rv;
}
private IReadOnlyDictionary<string, OptionTheoInterpolationData>
_filter_for_publish(IReadOnlyDictionary<string, OptionTheoInterpolationData> all_theos) {
HashSet<string> syms = new HashSet<string>();
VolSurfaceUsageListImmutable usage = _bb.read_state(SparkTags.VolSurfaceUsageTag);
string current_user = _bb.read_state(SparkTags.CurrentUser).name;
foreach (var u in usage.UsageList) {
VolSurfaceInput vs_input =
_bb.read_state(SparkTags.VolSurfaceCommittedInputTag(u.VsId));
if (vs_input != null) {
if (vs_input.surface_settings.core_settings.vs_manager ==
current_user) {
syms.Add(u.SymbolName);
}
}
}
return
all_theos.Where(kv => syms.Contains(kv.Key)).ToDictionary(kv => kv.Key, kv => kv.Value);
}
private void _publish_data() {
SystemContractData sc_data = _bb.read_state(SparkTags.SystemContractsTag, null);
IReadOnlyDictionary<string, OptionTheoInterpolationData> all_theos =
_bb.read_state(SparkTags.AllInterpGreeks, null);
all_theos = _filter_for_publish(all_theos);
// find the symbol vs vs_id, get the committed vs, see if it is
// owned by the current user, and only then publish it
IReadOnlyDictionary<string, OptionDriverPriceMap> all_drivers =
_bb.read_state(SparkTags.AllOptionDriverBBOTag, null);
if (sc_data == null || all_theos == null || all_drivers == null)
@@ -26,12 +26,13 @@ namespace mbts.spark {
_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);
Log.Ui.info(
$"VolSurface '{expiration}.{column}' is_dirty changed to {n}. " +
$"commited: {committed_value}; candidate: {candidate_value}");
};
if (column.type.is_editable()) {
_is_dirty.Changed += (o, n) => {
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();
@@ -29,6 +29,7 @@ namespace mbts.spark.VolSurface {
class VolSurfaceGridVM : DisposableViewModelBase {
readonly VolSurfaceVM _parent;
readonly UserTuple _user;
readonly ObservableCollection<VolSurfaceDisplayGridExpiration> _expirations = new();
readonly DeferrableAction _invalidate_rows;
readonly ColumnsModel _columns_model;
@@ -41,10 +42,12 @@ namespace mbts.spark.VolSurface {
VolSurfaceVM vm,
VolSurfaceDisplayModel model,
ISet<string> hidden_columns,
ISet<VolSurfaceExpiration> hidden_expirations) {
ISet<VolSurfaceExpiration> hidden_expirations,
UserTuple user) {
Log.notnull(hidden_columns);
Log.notnull(hidden_expirations);
_parent = vm;
_user = user;
this.model = model;
_columns_model = new(create_exp_column_view());
_hidden_columns = hidden_columns;
@@ -83,7 +86,7 @@ namespace mbts.spark.VolSurface {
_columns_model);
VolSurfaceRowVM row_factory(VolSurfaceDisplayGridExpiration exp) =>
new(this, exp);
new(this, exp, _user);
IDisposable connect_row(VolSurfaceRowVM row) {
row.request_calculate += request_recalc;
@@ -1,5 +1,6 @@
#nullable enable
namespace mbts.spark {
using bts;
using bts.collections;
using mbts.spark.VolSurface;
@@ -9,6 +10,7 @@ namespace mbts.spark {
using mbts.ui.utility;
using Spark.Core.Disposables;
using Spark.Core.Reactive;
using System;
using System.Collections.Generic;
@@ -22,6 +24,10 @@ namespace mbts.spark {
readonly VolSurfaceGridVM _parent;
readonly Property<VolSurfaceColumn?> _column;
readonly Property<DIYGridSuperHeaderVM?> _super_header;
readonly UserTuple _user;
readonly Property<bool> _is_open;
readonly DelegateProperty<string> _vs_manager;
readonly List<IDisposable> _resources = new();
ICommand? _revert_cmd;
ICommand? _shift_selection_cmd;
@@ -34,21 +40,29 @@ namespace mbts.spark {
ICommand? _copy_all_to_clipboard_cmd;
ICommand? _smart_copy_rolls_rates_cmd;
ICommand? _import_csv_cmd;
ObservantCommand? _acquire_ownership_cmd;
public VolSurfaceRowContextMenuVM(VolSurfaceGridVM parent, VolSurfaceRowVM row) {
public VolSurfaceRowContextMenuVM(VolSurfaceGridVM parent, VolSurfaceRowVM row, UserTuple user) {
_parent = parent;
_row = row;
_user = user;
_column = backing<VolSurfaceColumn?>(nameof(column));
_super_header = backing<DIYGridSuperHeaderVM?>(nameof(super_header));
_vs_manager = backing(
nameof(vs_manager),
() => _parent.model.get_active_settings()?.core_settings?.vs_manager ?? string.Empty);
_is_open = backing(nameof(is_open), false);
_dispose = Disposable.Create(
_resources.AddRange(
_column.invalidate_others_on_change(nameof(column_name)),
_super_header.invalidate_others_on_change(nameof(group_name)),
_is_open.Subscribe(_ => _vs_manager.refresh()),
_parent.visible_rows.ObserveSelf()
.BufferLatest(TimeSpan.FromSeconds(1))
.OnDispatcher()
.Subscribe(_ => sync_symbols()));
_dispose = Disposable.Create(() => _resources.DisposeAll(true));
void sync_symbols() {
var visible_exps = _parent.visible_rows.Map(r => r.expiration.symbol);
symbols.sync_with_models(
@@ -164,6 +178,34 @@ namespace mbts.spark {
_parent.model.csv_importing_enabled,
null);
public ICommand acquire_ownership_cmd {
get {
if (_acquire_ownership_cmd is null) {
_acquire_ownership_cmd = new(
() => {
var settings = _parent.model.get_active_settings();
if (settings is null) {
Log.Ui.error("Unable to acquire volsurface ownership: settings are null.");
return;
}
settings.core_settings.vs_manager = _user.name;
_parent.model.set_candidate_settings(settings);
});
_resources.Add(_vs_manager.observe_current(true)
.Subscribe(SelectorObserver.builder(_acquire_ownership_cmd).wrap<string>(
curr => curr != _user.name)));
}
return _acquire_ownership_cmd;
}
}
public bool is_open {
get => _is_open.Value;
set => _is_open.set(value);
}
public string vs_manager => _vs_manager.Value;
VolSurfaceDisplayGridColumn _assert_model() =>
column?.model ?? throw new InvalidOperationException();
@@ -1,5 +1,7 @@
#nullable enable
namespace mbts.spark.VolSurface {
using bts;
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.shell;
@@ -16,14 +18,16 @@ namespace mbts.spark.VolSurface {
readonly VolSurfaceGridVM _parent;
readonly VolSurfaceDisplayGridExpiration _exp;
readonly Dictionary<string, CellData> _cells = new();
readonly UserTuple _user;
readonly DeferrableAction _request_calculate;
VolSurfaceRowContextMenuVM? _context_menu;
bool _is_selected;
public VolSurfaceRowVM(VolSurfaceGridVM parent, VolSurfaceDisplayGridExpiration exp) {
public VolSurfaceRowVM(VolSurfaceGridVM parent, VolSurfaceDisplayGridExpiration exp, UserTuple user) {
_parent = parent;
_exp = exp;
_user = user;
_request_calculate = new(() => request_calculate?.Invoke());
_dispose = Disposable.Create(() => {
_cells.Values.DisposeAll();
@@ -49,7 +53,7 @@ namespace mbts.spark.VolSurface {
}
public VolSurfaceRowContextMenuVM context_menu =>
_context_menu ??= new(_parent, this);
_context_menu ??= new(_parent, this, _user);
public VolSurfaceCellVM get_cell(VolSurfaceDisplayGridColumn column) =>
_cells.GetOrAdd(column.unique_col_name, _ => _create_cell(column)).vm;
@@ -0,0 +1,89 @@
#nullable enable
namespace mbts.spark {
using bts.api.domain;
using mbts.analytics;
using mbts.ui.shell;
using mbts.ui.utility;
using System;
using System.Collections.Generic;
using VolCurveFitRegion = analytics.VolSurfaceEnums.VolCurveFitRegion;
public class VolSurfaceAutoFitSettingsVM : DisposableViewModelBase {
readonly Property<VolCurveFitRegion> _fit_region;
readonly Property<uint?> _period_secs;
readonly Property<double?> _driver_points_moved;
readonly Property<double?> _atm_points_moved;
readonly Property<bool> _is_auto_fit_enabled;
public VolSurfaceAutoFitSettingsVM() {
_fit_region = backing(nameof(fit_region), VolCurveFitRegion.None);
_is_auto_fit_enabled = backing(
nameof(is_auto_fit_enabled),
_fit_region.observe_current(true),
r => r != VolCurveFitRegion.None);
_period_secs = backing<uint?>(nameof(period_secs), 10);
_driver_points_moved = backing<double?>(nameof(driver_points_moved));
_atm_points_moved = backing<double?>(nameof(atm_points_moved));
_fit_region.Changed += (o, n) => RaisePropertyChanged(nameof(is_auto_fit_enabled));
}
public IEnumerable<VolCurveFitRegion> fit_regions =>
EnumHelper.get_values<VolCurveFitRegion>();
public VolCurveFitRegion fit_region {
get => _fit_region.Value;
set => _fit_region.set(value);
}
public bool is_auto_fit_enabled => _is_auto_fit_enabled.Value;
public uint? period_secs {
get => _period_secs.Value;
set => _period_secs.set(value);
}
public double? driver_points_moved {
get => _driver_points_moved.Value;
set => _driver_points_moved.set(value);
}
public TickDisplaySettingsImmutable? driver_points_display =>
user.settings.TickFactors.pennies.to_api_tick_display_settingsi();
public double? atm_points_moved {
get => _atm_points_moved.Value;
set => _atm_points_moved.set(value);
}
public TickDisplaySettingsImmutable? atm_points_display =>
user.settings.TickFactors.pennies.to_api_tick_display_settingsi();
public void load_from(VolSurfaceAutoFitSettings value) {
fit_region = value?.auto_fit_region ?? VolCurveFitRegion.None;
period_secs = value?.time_based_settings?.period_seconds;
driver_points_moved = value?.driver_move_based_settings?.points_moved;
atm_points_moved = value?.atm_implied_vol_based_settings?.points_moved;
}
public void assign_to(VolSurfaceAutoFitSettings value) {
if (value is null) {
throw new ArgumentNullException(nameof(value));
}
value.auto_fit_region = fit_region;
value.time_based_settings = new() {
period_seconds = period_secs
};
value.driver_move_based_settings = new() {
points_moved = driver_points_moved
};
value.atm_implied_vol_based_settings = new() {
points_moved = atm_points_moved
};
}
}
}
@@ -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);
}
}
@@ -40,6 +40,7 @@ namespace mbts.spark {
vol_model_cubic_spline_vm.load_from(settings.spline_model_settings);
vol_model_dual_quadratic_vm.load_from(settings.dualquadratic_model_settings);
vol_path_parabolic_vm.load_from(settings.core_settings.volpath_settings.parabolic_vol_path_settings);
auto_fit_vm.load_from(settings.core_settings.market_fit_settings.vs_auto_fit_settings);
init_rotation_vms(call_rotations, _core_settings.call_rotation.strike_vol_movement_pairs);
init_rotation_vms(put_rotations, _core_settings.put_rotation.strike_vol_movement_pairs);
@@ -105,6 +106,7 @@ namespace mbts.spark {
}).ToList();
_core_settings.strangle.strike_vol_movement_pairs = strangles.SelectMany(r => new[] { Tuple.Create(r.target_put_strike, r.put_move), Tuple.Create(r.target_call_strike, r.call_move) }).ToList();
_core_settings.atm_shift.atm_strike_vol_movement = atm_shifts.Count == 1 ? atm_shifts[0].move : 0;
auto_fit_vm.assign_to(_core_settings.market_fit_settings.vs_auto_fit_settings);
commit(_settings);
}
@@ -233,23 +235,7 @@ namespace mbts.spark {
}
}
public bool enable_auto_fit {
get => _core_settings.market_fit_settings.enable_auto_fit;
set {
using var _ = detect_property_change();
_core_settings.market_fit_settings.enable_auto_fit = value;
}
}
public VolSurfaceEnums.VolCurveFitRegion auto_fit_region {
get => _core_settings.market_fit_settings.auto_fit_region;
set { _core_settings.market_fit_settings.auto_fit_region = value; }
}
public double auto_fit_time_ms {
get => _core_settings.market_fit_settings.auto_fit_time_ms;
set { _core_settings.market_fit_settings.auto_fit_time_ms = value; }
}
public VolSurfaceAutoFitSettingsVM auto_fit_vm { get; } = new();
public bool auto_decay_vol_time {
get => _core_settings.time_settings.time_mode == VolSurfaceEnums.VolSurfaceTimeMode.AutoDecay;
+10 -2
View File
@@ -1,5 +1,6 @@
#nullable enable
namespace mbts.spark {
using bts;
using bts.api;
using bts.collections;
@@ -27,6 +28,7 @@ namespace mbts.spark {
readonly IBus _bus;
readonly string _request_id = Guid.NewGuid().ToString();
readonly VolSurfaceDisplayModel _model;
readonly UserTuple _user;
readonly IRaiseCanExecuteChangedCommand _revert_cmd;
readonly IRaiseCanExecuteChangedCommand _commit_cmd;
readonly IDialogCommand _main_settings_cmd;
@@ -38,10 +40,16 @@ namespace mbts.spark {
bool _ignore_implied_vol_settings;
public VolSurfaceVM(
VolSurfaceDisplayModel model, int id, IBus bus, VolSurfaceWindowSettings startup_data) {
VolSurfaceDisplayModel model,
int id,
IBus bus,
VolSurfaceWindowSettings startup_data,
UserTuple user
) {
_model = model;
_vs_id = id;
_bus = bus;
_user = user;
macro_actions = new VolSurfaceMacroActionsVM(_model);
globals = new VolSurfaceGlobalParameterVM(_model);
@@ -49,7 +57,7 @@ namespace mbts.spark {
_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);
this, _model, _grid_settings.hidden_cols(), hidden_exps_set, _user);
grid.on_selection_changed += _on_grid_selection_changed;
_model.publish_grid_settings(_grid_settings);
@@ -145,7 +145,7 @@ namespace mbts {
!(x == y);
public override string ToString() =>
$"{security_tuple} {expiration.ToShortDateString()}";
$"{security_tuple} {SecurityFormatter.format_expiration(expiration)}";
}
[ProtoContract]
@@ -4,13 +4,11 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace mbts.analytics
{
namespace mbts.analytics {
/// These are the VolSurface settings that are common
/// to any Vol Model
[ProtoBuf.ProtoContract(Name = "VolSurfaceCoreSettings")]
public class VolSurfaceCoreSettings
{
public class VolSurfaceCoreSettings {
[ProtoBuf.ProtoMember(1)]
public string vol_surface_name;
[ProtoBuf.ProtoMember(2)]
@@ -87,5 +85,7 @@ namespace mbts.analytics
get => _time_settings ??= new();
set => _time_settings = value;
}
[ProtoBuf.ProtoMember(240)]
public string vs_manager { get; set; } = string.Empty;
}
}
@@ -75,6 +75,7 @@ namespace mbts.analytics {
if (core_settings.market_fit_settings == null) {
core_settings.market_fit_settings = new VolSurfaceMarketFitSettings();
}
core_settings.market_fit_settings.vs_auto_fit_settings ??= new();
if (core_settings.time_settings == null) {
core_settings.time_settings = new VolSurfaceTimeSettings();
}
@@ -141,6 +141,7 @@ namespace mbts.analytics
public enum VolCurveFitRegion
{
None,
ATM,
All
}
@@ -230,4 +231,4 @@ namespace mbts.analytics
USE_CALENDAR_FOR_BUSINESS
}
}
}
}
@@ -4,11 +4,9 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace mbts.analytics
{
namespace mbts.analytics {
[ProtoBuf.ProtoContract(Name = "VolSurfaceMarketFitSettings")]
public class VolSurfaceMarketFitSettings
{
public class VolSurfaceMarketFitSettings {
/// use one sided market or not
[ProtoBuf.ProtoMember(10)]
public bool ignore_one_sided_markets;
@@ -22,19 +20,44 @@ namespace mbts.analytics
public double graph_update_period_ms = 2500;
/// If this is set to true a regression curve is drawn
/// and the vol model adheres to that
[ProtoBuf.ProtoMember(50)]
[ProtoBuf.ProtoMember(50)]
public bool use_weighted_regression_fit = false;
[ProtoBuf.ProtoMember(55)]
public uint regression_order = 4;
/// The system auto fits and saves vols if this is
/// set to true
[ProtoBuf.ProtoMember(60)]
public bool enable_auto_fit = false;
/// If enable_auto_fit = true, this governs
/// how often the system auto-fits
[ProtoBuf.ProtoMember(70)]
public double auto_fit_time_ms = 30000;
[ProtoBuf.ProtoMember(80)]
public VolSurfaceEnums.VolCurveFitRegion auto_fit_region = VolSurfaceEnums.VolCurveFitRegion.ATM;
[ProtoBuf.ProtoMember(90)]
public VolSurfaceAutoFitSettings vs_auto_fit_settings { get; set; }
}
[ProtoBuf.ProtoContract(Name = "VolSurfaceAutoFitSettings")]
public class VolSurfaceAutoFitSettings {
// each of these settings can be enabled independently. if they are enabled
// then any of them being true will result in an autmatic fit
[ProtoBuf.ProtoContract(Name = "TimeBasedSettings")]
public class TimeBasedSettings {
[ProtoBuf.ProtoMember(10)]
public uint? period_seconds { get; set; }
}
[ProtoBuf.ProtoContract(Name = "DriverMoveBasedSettings")]
public class DriverMoveBasedSettings {
[ProtoBuf.ProtoMember(10)]
public double? points_moved { get; set; }
}
[ProtoBuf.ProtoContract(Name = "ATMImpliedVolBasedSettings")]
public class ATMImpliedVolBasedSettings {
[ProtoBuf.ProtoMember(20)]
public double? points_moved { get; set; }
// we can do price terms moved as well
}
[ProtoBuf.ProtoMember(5)]
public VolSurfaceEnums.VolCurveFitRegion auto_fit_region;
[ProtoBuf.ProtoMember(10)]
public TimeBasedSettings time_based_settings = null;
[ProtoBuf.ProtoMember(20)]
public DriverMoveBasedSettings driver_move_based_settings = null;
[ProtoBuf.ProtoMember(30)]
public ATMImpliedVolBasedSettings atm_implied_vol_based_settings = null;
}
}
@@ -475,6 +475,7 @@ namespace mbts.analytics {
public static ResultMessage save_volsurface(
VolSurfaceInput vs_input, AnalyticsService service, string user = "") {
vs_input.saver_login = user;
vs_input.surface_settings.core_settings.vs_manager = user;
// convert to VolSurfaceEntry
var to_save = new VolSurfaceEntry();
var serialized_vs = ProtobufSerializationHelper.serialize(vs_input);
@@ -595,7 +596,7 @@ namespace mbts.analytics {
_greek_getter(g)(t, is_call);
public static IDictionary<double, IEnumerable<Theos>> hash_strikes(IEnumerable<Theos> theos) =>
theos.Map(t => t.strike);
theos.Map(t => t.strike);
static Func<Theos, bool, double> _greek_getter(VolSurfaceGreeks g) =>
g switch {
@@ -88,8 +88,8 @@ namespace mbts.analytics {
public void set_driver_price(
IDictionary<VolSurfaceExpiration, double> driver_price_map) {
Log.Gen.info($"VolSurfaceInterpGreeksProducer.set_driver_price " +
$"vs_id: {_vs_id} exp_count: {driver_price_map.Count}");
// Log.Gen.info($"VolSurfaceInterpGreeksProducer.set_driver_price " +
// $"vs_id: {_vs_id} exp_count: {driver_price_map.Count}");
_driver_price_map = new Dictionary<VolSurfaceExpiration, double>(driver_price_map);
_compute_and_fire(InputType.DriverPrice);
}
+4 -1
View File
@@ -135,7 +135,10 @@ namespace bts {
var meta = _security_metadata.get(smd.security);
if (meta.HasValue) {
exch_secs[smd.id] = new(
smd.security, smd.md, meta.Value.PriceDisplay, meta.Value.QuantityDisplay);
smd.security,
smd.md,
meta.Value.HasPriceDisplay ? meta.Value.PriceDisplay : null,
meta.Value.HasQuantityDisplay ? meta.Value.QuantityDisplay : null);
}
}
_bus.post(SparkTags.ServerSecuritiesTag, exch_secs);
+1 -1
View File
@@ -62,7 +62,7 @@ namespace bts {
}
private void _on_server_sec_map(IReadOnlyDictionary<uint, SecurityMD> sec_map) {
_log_options(sec_map);
//_log_options(sec_map);
bts.Log.Gen.info(String.Format("MergedMDDaemon._on_server_sec_map sz: {0}", sec_map.Count()));
_server_sec_map = new Dictionary<uint, SecurityMD>(sec_map);
_merge_and_post();
@@ -56,7 +56,7 @@ namespace mbts.spark {
r => new ReportImmutable?(r),
r => r?.Id ?? throw new ArgumentNullException(nameof(r)));
_window_factories = new() {
new VolSurfaceWindowFactory(this, bus),
new VolSurfaceWindowFactory(this, bus, user.Value),
new AnalyticsExpirationParametersWindowFactory(this, bus),
new SlideReportWindowFactory(this, bus, reports_demuxer.subscribe),
new ComboReportWindowFactory(this, bus, reports_demuxer.subscribe),
@@ -793,70 +793,106 @@
Grid.Row="5"
Grid.Column="1"
Grid.ColumnSpan="4"
DataContext="{Binding auto_fit_vm}"
Header="Auto Fit"
Margin="0,5,0,0"
Padding="5"
IsEnabled="False">
Padding="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<CheckBox
Grid.ColumnSpan="2" Content="Enabled" IsChecked="{Binding enable_auto_fit}" />
<TextBlock Grid.Row="1" Text="Region" Margin="16,5,0,0">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger
Binding="{Binding enable_auto_fit}"
Value="False">
<Setter
Property="Foreground"
Value="Gray" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock Grid.Row="0" Text="Fit Region" />
<ComboBox
Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="2"
Margin="8,0,0,0"
VerticalAlignment="Center"
ItemsSource="{Binding fit_regions}"
SelectedItem="{Binding fit_region}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={x:Static shell:VolSurfaceSettingsEditor.AutoFitRegionDisplayTextConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock
Grid.Row="1"
Margin="0,5,0,0"
Text="Every" />
<c:TickUpDownNullableUInt32
Grid.Row="1"
Grid.Column="1"
Margin="12,0,0,0"
HorizontalAlignment="Stretch"
ItemsSource="{Binding auto_fit_region_choices}"
SelectedValue="{Binding auto_fit_region}"
IsEnabled="{Binding enable_auto_fit}" />
HorizontalAlignment="Left"
VerticalAlignment="Center"
Minimum="30"
Margin="8,0,0,0"
Width="60"
Value="{Binding period_secs}"
IsEnabled="{Binding is_auto_fit_enabled}" />
<TextBlock
Grid.Row="1"
Grid.Column="2"
HorizontalAlignment="Left"
Margin="3,5,0,0"
Text="secs" />
<TextBlock Grid.Row="2" Text="Fit Time" Margin="16,5,0,0">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding enable_auto_fit}" Value="False">
<Setter Property="Foreground" Value="Gray" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<c:TextBoxDouble
<TextBlock
Grid.Row="2"
Margin="0,5,0,0"
Text="When Driver moves" />
<c:TickUpDownNullableDouble
Grid.Row="2"
Grid.Column="1"
c:TextBoxEx.Suffix="ms"
ToolTipService.ShowOnDisabled="True"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="8,0,0,0"
Width="60"
Margin="12,5,0,0"
IsEnabled="{Binding enable_auto_fit}"
Value="{Binding auto_fit_time_ms}"
Template="{StaticResource SuffixTemplate}" />
Value="{Binding driver_points_moved}"
Increment="0.01"
TickDisplaySettings="{Binding driver_points_display}"
IsEnabled="False"
ToolTip="Not yet supported (coming soon)" />
<TextBlock
Grid.Row="2"
Grid.Column="2"
HorizontalAlignment="Left"
Margin="3,5,0,0"
Text="%" />
<TextBlock
Grid.Row="3"
Margin="0,5,0,0"
Text="When ATM moves" />
<c:TickUpDownNullableDouble
Grid.Row="3"
Grid.Column="1"
ToolTipService.ShowOnDisabled="True"
HorizontalAlignment="Left"
Margin="8,0,0,0"
Width="60"
Value="{Binding atm_points_moved}"
Increment="0.01"
TickDisplaySettings="{Binding atm_points_display}"
IsEnabled="False"
ToolTip="Not yet supported (coming soon)" />
<TextBlock
Grid.Row="3"
Grid.Column="2"
HorizontalAlignment="Left"
Margin="3,5,0,0"
Text="%" />
</Grid>
</GroupBox>
</Grid>
@@ -1,9 +1,20 @@
#nullable enable
namespace mbts.ui.shell {
using mbts.analytics;
using mbts.ui.converters;
using System.Windows;
using System.Windows.Data;
partial class VolSurfaceSettingsEditor : Window {
public VolSurfaceSettingsEditor() =>
InitializeComponent();
public static IValueConverter AutoFitRegionDisplayTextConverter =>
ValueConverter.create<VolSurfaceEnums.VolCurveFitRegion, string>(fr =>
fr switch {
VolSurfaceEnums.VolCurveFitRegion.None => "Disabled",
_ => fr.ToString()
});
}
}
@@ -262,7 +262,7 @@
IsDragAdornerEnabled="False"
ContextMenuOpening="_on_context_menu_opening">
<c:DIYGrid.ContextMenu>
<ContextMenu>
<ContextMenu IsOpen="{Binding is_open}">
<MenuItem
Header="Populate Empty Expirations"
Command="{Binding populate_empty_exps_cmd}" />
@@ -413,6 +413,11 @@
</MenuItem.ItemContainerStyle>
</MenuItem>
<MenuItem Header="Import CSV..." Command="{Binding import_csv_cmd}" />
<MenuItem Command="{Binding acquire_ownership_cmd}">
<MenuItem.Header>
<TextBlock Text="{Binding vs_manager, StringFormat='Acquire ownership from \'{0}\''}" />
</MenuItem.Header>
</MenuItem>
</ContextMenu>
</c:DIYGrid.ContextMenu>
<c:DIYGrid.RowStyle>
@@ -122,7 +122,7 @@
}
var mouse_pos = Mouse.GetPosition(this);
if (!this.ChildAtPoint<VolSurfaceRowView>(mouse_pos, out var row)) {
cm.IsOpen = false;
cm.SetCurrentValue(ContextMenu.IsOpenProperty, false);
return;
}
var cgs = g.GetColumnGeometry().ToList();
@@ -1,4 +1,5 @@
namespace mbts.spark {
using bts;
using bts.api;
using bts.spark;
@@ -14,14 +15,20 @@
public const string WINDOW_TYPE = "VolSurface";
readonly VolSurfaceWindowSettings _startup_data;
readonly UserTuple _user;
VolSurfaceVM _vm;
VolSurfaceView _view;
public VolSurfaceWindow(
VolSurfaceWindowFactory factory, IBus bus, string vs_name, VolSurfaceWindowSettings startup_data) :
base(vs_name, bus, factory, Icons.vol_surface) {
VolSurfaceWindowFactory factory,
IBus bus,
string vs_name,
VolSurfaceWindowSettings startup_data,
UserTuple user
) : base(vs_name, bus, factory, Icons.vol_surface) {
_startup_data = startup_data ?? throw new ArgumentNullException(nameof(startup_data));
_user = user;
this.vs_name = vs_name;
_dispose = Disposable.Create(() => Disposable.dispose(ref _vm));
}
@@ -37,7 +44,7 @@
public override UIElement Content => _view;
public void thread_init() {
_vm = new VolSurfaceVM(new VolSurfaceDisplayModel(vs_id, _bus, true), vs_id, _bus, _startup_data);
_vm = new VolSurfaceVM(new (vs_id, _bus, true), vs_id, _bus, _startup_data, _user);
_view = new VolSurfaceView {
DataContext = _vm
};
@@ -1,4 +1,5 @@
namespace mbts.spark {
using bts;
using bts.api;
using bts.shell;
@@ -10,10 +11,12 @@ namespace mbts.spark {
class VolSurfaceWindowFactory : ShellWindowFactory<VolSurfaceWindowSettings> {
readonly IBus _bus;
readonly UserTuple _user;
public VolSurfaceWindowFactory(IShellModule module, IBus bus)
public VolSurfaceWindowFactory(IShellModule module, IBus bus, UserTuple user)
: base(module, "VolSurface") {
_bus = bus;
_user = user;
_dispose = bus.subscribe(SparkTags.ShowVolSurface).OnDispatcher().Subscribe(
async state => _bus.post(SparkTags.ShowWindow, await _create(state)));
}
@@ -22,7 +25,7 @@ namespace mbts.spark {
_create(state);
async Task<IShellWindow> _create(VolSurfaceWindowSettings state) =>
new VolSurfaceWindow(this, _bus, await _lookup_vs_name(state.id), state);
new VolSurfaceWindow(this, _bus, await _lookup_vs_name(state.id), state, _user);
async Task<string> _lookup_vs_name(int vs_id) {
var (vol_surfaces, success) = await _bus.subscribe(SparkTags.VolSurfaceListTag).FirstAsyncTask(TimeSpan.FromSeconds(2));
@@ -31,7 +31,7 @@
_window_factories = new() {
new MarketViewWindowFactory(
this, bus, settings_hub, orders_model, position_model, sec_meta_store),
new OptionsViewWindowFactory(this, bus),
new OptionsViewWindowFactory(this, orders_model, bus),
new TimeAndSalesWindowFactory(this, bus, consumer, settings_hub, orders_model.security_auxiliary_model),
};
@@ -79,10 +79,12 @@ namespace bts.shell.market_view {
var ask_col_index = columns.FindIndex(x => x.id == MarketViewWindowFactory.col_id(Columns.Ask));
if (bid_col_index > -1 && ask_col_index > -1) {
if (!columns[bid_col_index].background_color_override.HasValue) {
columns[bid_col_index] = columns[bid_col_index].with(background_color_override: new NullableColorProto(BTSColors.MarketData.bid.value));
columns[bid_col_index] = columns[bid_col_index].with(
background_color_override: new(BTSColors.MarketData.bid));
}
if (!columns[ask_col_index].background_color_override.HasValue) {
columns[ask_col_index] = columns[ask_col_index].with(background_color_override: new NullableColorProto(BTSColors.MarketData.ask.value));
columns[ask_col_index] = columns[ask_col_index].with(
background_color_override: new(BTSColors.MarketData.ask));
}
}
// and enable background color upgrade
@@ -70,11 +70,13 @@ namespace bts.shell {
bool applied = false;
if (bid_col_index > -1 && ask_col_index > -1) {
if (!columns[bid_col_index].background_color_override.HasValue) {
columns[bid_col_index] = columns[bid_col_index].with(background_color_override: new NullableColorProto(BTSColors.MarketData.bid.value));
columns[bid_col_index] = columns[bid_col_index].with(
background_color_override: new(BTSColors.MarketData.bid));
applied = true;
}
if (!columns[ask_col_index].background_color_override.HasValue) {
columns[ask_col_index] = columns[ask_col_index].with(background_color_override: new NullableColorProto(BTSColors.MarketData.ask.value));
columns[ask_col_index] = columns[ask_col_index].with(
background_color_override: new(BTSColors.MarketData.ask));
applied = true;
}
}
@@ -10,12 +10,14 @@ namespace mbts.spark {
class OptionsViewWindowFactory : ShellWindowFactory<OptionsViewSettings> {
readonly IBus _bus;
readonly NMSheetAllTaskingDataSource _tasking_datasource;
public OptionsViewWindowFactory(IShellModule module, IBus bus)
public OptionsViewWindowFactory(IShellModule module, OrdersModel orders_model, IBus bus)
: base(module, OptionsViewWindow.WINDOW_TYPE) {
_bus = bus;
_dispose = bus.subscribe(SparkTags.show_default_options_view).OnDispatcher().Subscribe(
sc => _bus.post(SparkTags.ShowWindow, _create(OptionsViewSettings.Default(sc))));
_tasking_datasource = new NMSheetAllTaskingDataSource(orders_model, bus);
}
public override Task<IShellWindow> load(OptionsViewSettings state) =>
@@ -176,10 +176,11 @@
</usp:DataGridParameterCellTemplateConverter.QuantityMeasureTemplate>
</usp:DataGridParameterCellTemplateConverter>
<Style x:Key="ExpanderToggleButton" TargetType="ToggleButton">
<Setter Property="Foreground" Value="{u:BTSColor ExecutionStrategy.expander_foreground}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid Background="Transparent">
<Grid Background="{u:BTSColor ExecutionStrategy.expander_background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="12" />
<ColumnDefinition/>
@@ -190,7 +191,7 @@
HorizontalAlignment="Center"
Margin="0,5,0,0"
SnapsToDevicePixels="False"
Stroke="#77333333"
Stroke="{u:BTSColor ExecutionStrategy.arrow_background}"
StrokeThickness="2"
VerticalAlignment="Top"
/>
@@ -199,6 +200,7 @@
ContentSource="{TemplateBinding Content}"
Margin="3,0,0,0"
/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
@@ -211,7 +213,7 @@
<Setter Property="Stroke" TargetName="arrow" Value="Black"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Stroke" TargetName="arrow" Value="#FF707070"/>
<Setter Property="Stroke" TargetName="arrow" Value="{u:BTSColor ExecutionStrategy.arrow_background_selected}"/>
<Setter Property="Foreground" Value="Gray"/>
</Trigger>
</ControlTemplate.Triggers>
@@ -278,7 +280,8 @@
<ColumnDefinition/>
</SelectiveScrollingGrid.ColumnDefinitions>
<DataGridRowHeader
Background="Transparent"
Foreground="{u:BTSColor ExecutionStrategy.expander_foreground}"
Background="{u:BTSColor ExecutionStrategy.data_grid_row_header_background}"
Padding="{Binding section_count, Converter={StaticResource RowHeaderGroupIndentConverter}}"
FontWeight="{Binding font_weight, FallbackValue={u:FontWeight Normal}}"
SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical"
@@ -317,9 +320,17 @@
<Style x:Key="DataGridRowStyle" TargetType="DataGridRow">
<Setter Property="BorderThickness" Value="1,0"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Background" Value="{u:BTSColor ExecutionStrategy.alternate_column_background}"/>
<Setter Property="Template" Value="{StaticResource DataGridRowTemplate}"/>
<Setter Property="usp:ExecutionStrategyEditor.RowHasErrors" Value="{Binding has_errors}"/>
<Style.Triggers>
<Trigger Property="ListBox.AlternationIndex" Value="1">
<Setter Property="Background" Value="{u:BTSColor ExecutionStrategy.data_grid_background}"/>
</Trigger>
<!-- <Trigger Property="ListBox.AlternationIndex" Value="2">
<Setter Property="Background" Value="LightBlue"/>
<Setter Property="Foreground" Value="Navy"/>
</Trigger> -->
<DataTrigger Binding="{Binding read_only}" Value="True">
<Setter Property="TextElement.Foreground" Value="{u:BTSColor UI.input_disabled_text_dark}"/>
<Setter Property="ToolTip">
@@ -57,7 +57,7 @@ namespace mbts.spark {
main_vm.rows.AddRange(parsed_synths.Select(ps => {
var sec = ps.result;
var r = new SyntheticImportRowVM(orders_model.admin_model.user.id, used_names.Contains) {
tick_factors = TickUtils.get_regional_ticks(sec.ContractSpec).low_tick,
tick_factors = TickUtils.get_regional_ticks(sec.immutable()).low_tick,
name = sec.Synthetic.Name,
parsed_synth = ps
};
@@ -56,7 +56,7 @@ namespace mbts.spark {
public SyntheticEditorVM(SpreaderModel model, SecurityImmutable synthetic, ExecutionStrategyImmutable strategy, IObservable<bool> security_has_working_orders)
: this(synthetic, strategy, false) {
ExceptionAssert.InvalidOperation.That(synthetic.Id != 0, "This constructor may only be used for already-existing synthetic securities (id must be non-zero).");
_tick_factors = TickUtils.get_regional_ticks(synthetic.ContractSpec).low_tick;
_tick_factors = TickUtils.get_regional_ticks(synthetic).low_tick;
if (TickUtils.is_integer_tick(synthetic.ContractSpec)) {
_use_fractional_ticks = false;
_integer_tick_size = DoubleHelper.to_optional_int32(synthetic.ContractSpec.LowTick) ?? 0;
@@ -112,7 +112,7 @@ namespace mbts.spark {
_set_ticks_automatically = false;
_set_quantities_automatically = false;
_set_price_mults_automatically = false;
_tick_factors = TickUtils.get_regional_ticks(_synthetic.ContractSpec).low_tick;
_tick_factors = TickUtils.get_regional_ticks(_synthetic.immutable()).low_tick;
} else {
_deduce_name();
_deduce_ticks();
@@ -411,7 +411,7 @@ namespace mbts.spark {
}
void _deduce_ticks() {
_tick_factors = TickUtils.deduce_ticks(leg_tuples.Select(l => l.leg.Security.ContractSpec));
_tick_factors = TickUtils.deduce_ticks(leg_tuples.Select(l => l.leg.Security.immutable()));
RaisePropertyChanged(nameof(tick_factors));
}
@@ -371,6 +371,7 @@
<usp:AlgoEditorView
DataContext="{Binding selected_definition}"
Background="Transparent"
Foreground="{u:BTSColor UI.default_text}"
BorderBrush="{Binding algo_root, Converter={StaticResource OrderTypeBrushConverter}}"
Padding="12,8" />
</ScrollViewer>
@@ -79,7 +79,7 @@ namespace Spark.Trading {
meta.Value.Value.PriceDisplay : Security.Defaults.price_display_settingsi;
if (security.HasValue) {
rv = rv.with(
tick_factors: security.spec_or_default().tick_factors().to_api_tick_factors());
tick_factors: security.Value.tick_factors().to_api_tick_factors());
}
return rv;
}
@@ -410,13 +410,13 @@ namespace mbts.spark {
day_change = new DaySettings {
// (neutral)
font = _default_font,
background_color = Colors.Transparent.rgb_color(),
background_color = Colors.Transparent.to_uint(),
// negative
negative_font_color = Colors.White.rgb_color(),
negative_background_color = Colors.Red.rgb_color(),
negative_font_color = Colors.White.to_uint(),
negative_background_color = Colors.Red.to_uint(),
// positive
positive_font_color = Colors.White.rgb_color(),
positive_background_color = Colors.Green.rgb_color()
positive_font_color = Colors.White.to_uint(),
positive_background_color = Colors.Green.to_uint()
},
session_low = _default_item,
session_high = _default_item,
@@ -431,8 +431,8 @@ namespace mbts.spark {
public static LadderPanelPricePointSettings tt_default {
get {
var rv = historic_default;
rv.day_change.background_color = Color.FromRgb(113, 201, 69).rgb_color();
rv.day_change.font.font_color = Colors.Black.rgb_color();
rv.day_change.background_color = Color.FromRgb(113, 201, 69).to_uint();
rv.day_change.font.font_color = Colors.Black.to_uint();
return rv;
}
}
@@ -484,7 +484,7 @@ namespace mbts.spark {
static ItemSettings _default_item =>
new ItemSettings {
font = _default_font,
background_color = Colors.Transparent.rgb_color()
background_color = Colors.Transparent.to_uint()
};
[ProtoContract]
@@ -97,7 +97,7 @@ namespace mbts.spark {
security_key = use_self_security ? null : selected_security_key,
price_type = _selected_price_type,
display = new LadderMarketBreakLine {
color = color.rgb_color(),
color = color.to_uint(),
show = show,
refresh_mode = refresh_mode
}
@@ -27,7 +27,7 @@ namespace mbts.spark {
class LadderOrderVM : DisposableViewModelBase {
static readonly Color _colorbg = Colors.White;
static readonly Color _darkbg = Color.FromRgb(0xbf, 0xbf, 0xbf);
static readonly Brush _color_bg_brush = _colorbg.rgb_color().rgb_brush();
static readonly Brush _color_bg_brush = _colorbg.to_uint().rgb_brush();
readonly LadderVM _owner;
readonly double _real_price;
@@ -228,7 +228,7 @@ namespace mbts.spark {
if (_orders.TryGetValue(order.Key, out var opm)) {
algo_studio_abbreviation = (opm.meta?.abbreviation).is_null_or_empty() ?
_abbreviate_algo(opm.algo) : opm.meta?.abbreviation ?? string.Empty;
border = opm.meta?.badge_color?.rgb_color().rgb_brush() ?? border;
border = opm.meta?.badge_color?.to_uint().rgb_brush() ?? border;
}
algo_type = order.order_type().is_bts_algo_type() ?
order.order_type() : CustomOrderDefinition.CustomOneofCase.None;
@@ -241,7 +241,7 @@ namespace mbts.spark {
}
public OrderBookVM? create_orderbook_vm() {
var ticks = _owner.spec.full_ticks_from_zero(real_price);
var ticks = _owner.spec.count_ticks(real_price);
if (!ticks.HasValue) {
return null;
}
@@ -42,13 +42,13 @@ namespace mbts.spark {
public LadderPanelPricePointSettings.ItemSettings create() =>
new LadderPanelPricePointSettings.ItemSettings {
font = new FontParamsProto {
font_color = font_color.rgb_color(),
font_color = font_color.to_uint(),
font_size = font_size,
typeface = new(
font_family.name() ?? TextUtils.StandardFontFamilyName,
font_weight.ToOpenTypeWeight())
},
background_color = background_color.rgb_color(),
background_color = background_color.to_uint(),
show_label = show_label
};
@@ -111,11 +111,11 @@ namespace mbts.spark {
show_label = base_settings.show_label,
background_color = base_settings.background_color,
// negative
negative_font_color = negative_font_color.rgb_color(),
negative_background_color = negative_background_color.rgb_color(),
negative_font_color = negative_font_color.to_uint(),
negative_background_color = negative_background_color.to_uint(),
// positive
positive_font_color = positive_font_color.rgb_color(),
positive_background_color = positive_background_color.rgb_color()
positive_font_color = positive_font_color.to_uint(),
positive_background_color = positive_background_color.to_uint()
};
}
}
@@ -191,7 +191,7 @@ namespace mbts.spark {
void increment_ticks_per_row() {
var tpr = ticks_per_row;
for (uint i = 1; i < 100; i++) {
var new_tpr = TickUtils.fit_ticks_per_row_to_dollars(security.ContractSpec, ticks_per_row + i);
var new_tpr = TickUtils.fit_ticks_per_row_to_dollars(security, ticks_per_row + i);
if (new_tpr != tpr) {
ticks_per_row = new_tpr;
break;
@@ -201,7 +201,7 @@ namespace mbts.spark {
void decrement_ticks_per_row() {
var tpr = ticks_per_row;
for (uint i = 1; i < tpr; i++) {
var new_tpr = TickUtils.fit_ticks_per_row_to_dollars(security.ContractSpec, tpr - i);
var new_tpr = TickUtils.fit_ticks_per_row_to_dollars(security, tpr - i);
if (new_tpr != tpr) {
ticks_per_row = new_tpr;
break;
@@ -239,7 +239,8 @@ namespace mbts.spark {
// since settings profiles may be shared among ladders
// of different securities/tick sizes, the ticks per row setting
// may need to be rounded to a number that is a factor of $1.00
public uint? rounded_ticks_per_row => TickUtils.fit_ticks_per_row_to_dollars(_security.ContractSpec, ticks_per_row);
public uint? rounded_ticks_per_row =>
TickUtils.fit_ticks_per_row_to_dollars(_security, ticks_per_row);
public MarketSizeDisplayVM size_display { get; } = new MarketSizeDisplayVM();
public SimpleGridSettingsVM mini_ob { get; } = new SimpleGridSettingsVM(OrderBookGridSettingsManager.hard_column_flags);
@@ -700,8 +701,8 @@ namespace mbts.spark {
font_weight = font_weight.ToOpenTypeWeight(),
width = width,
show = show,
foreground = foreground.rgb_color(),
background = background.rgb_color()
foreground = foreground.to_uint(),
background = background.to_uint()
};
}
}
@@ -99,7 +99,7 @@ namespace mbts.spark {
IReadOnlyDictionary<uint, OrderSecurity> _cache = DictionaryHelper.empty<uint, OrderSecurity>();
ImmutableDictionary<AlgoKey, LadderFavoriteAlgoMetadata> _favorite_algo_metadata_map =
ImmutableDictionary<AlgoKey, LadderFavoriteAlgoMetadata>.Empty;
ContractSpecificationImmutable? _spec;
RegionalTickFactors? _spec;
LadderVM(
IBus bus,
@@ -243,10 +243,9 @@ namespace mbts.spark {
var orders_source = settings.Select(s => s.ticks_per_row).DistinctUntilChanged()
.SelectSeries(tpr => {
var spec = TickUtils.multiply_tick_size(security.ContractSpec, tpr);
var spec = TickUtils.multiply_tick_size(security.regional_ticks(), tpr);
var price_comp = Comparer<double>.Create((a, b) =>
Comparer<int?>.Default.Compare(
spec.full_ticks_from_zero(a), spec.full_ticks_from_zero(b)));
Comparer<long?>.Default.Compare(spec.count_ticks(a), spec.count_ticks(b)));
return _order_price_source(model.orders, price_comp, p => TickUtils.normalize_price(spec, p));
});
_day_change.Changed += (o, n) => RaisePropertyChanged(
@@ -394,9 +393,10 @@ namespace mbts.spark {
}
public SecurityImmutable security => _model.security;
public ContractSpecificationImmutable spec => _spec ?? (
public RegionalTickFactors spec => _spec ?? (
_spec = TickUtils.multiply_tick_size(
security.ContractSpec, current_settings?.ticks_per_row ?? 1)).Value;
security.regional_ticks(), current_settings?.ticks_per_row ?? 1))
?? RegionalTickFactors.Default;
public double display_quantity_divisor { get; }
public LadderSettings current_settings { get; private set; }
@@ -826,7 +826,7 @@ namespace mbts.spark {
if (!price.is_real()) {
msg = "not a real number";
} else if (settlement.is_real()) {
var ticks_from_settle = security.ContractSpec.tickdiff(price, settlement);
var ticks_from_settle = security.tickdiff(price, settlement);
if (ticks_from_settle.HasValue) {
var max_cross = (current_settings?.ladder_order_limits?.max_settlement_cross_ticks)
.as_nullable();
@@ -858,7 +858,7 @@ namespace mbts.spark {
} else {
ulong _ = 0;
_model.md.get_bbo(ref _, out var bid, out var ask);
var mid = TickUtils.mid_tick(security.ContractSpec, bid.price, ask.price);
var mid = TickUtils.mid_tick(security.regional_ticks(), bid.price, ask.price);
_day_change.set(mid - md.settlement_price);
}
_volume.set(volume);
@@ -32,6 +32,8 @@ using System.Windows.Media.Animation;
using System.Windows.Threading;
namespace mbts.spark {
using RegionalTickFactors = user.settings.RegionalTickFactors;
partial class LadderGridHost : Control {
static readonly int _initial_row_count;
static readonly bool _show_scrollbar;
@@ -83,7 +85,6 @@ namespace mbts.spark {
bool _price_dirty = false, _piq_dirty = false;
LadderPriceList _price_list = new() {
length = _initial_row_count,
spec = Security.Defaults.ContractSpecificationImmutable
};
LadderPriceList _pending_price_list = null;
IComparer<double> _price_comparer;
@@ -384,16 +385,16 @@ namespace mbts.spark {
Column[] _columns { get; set; } = Array.Empty<Column>();
IEnumerable<Column> _visible_columns => _columns.Where(c => c.settings.show);
ContractSpecificationImmutable? _spec_backing;
ContractSpecificationImmutable _spec {
RegionalTickFactors _spec_backing;
RegionalTickFactors _spec {
get {
if (_spec_backing.HasValue) {
return _spec_backing.Value;
if (_spec_backing is not null) {
return _spec_backing;
} else if (_vm != null) {
_spec_backing = TickUtils.multiply_tick_size(security.ContractSpec, _settings?.ticks_per_row ?? 1);
return _spec_backing.Value;
_spec_backing = TickUtils.multiply_tick_size(security.regional_ticks(), _settings?.ticks_per_row ?? 1);
return _spec_backing;
}
return Security.Defaults.ContractSpecificationImmutable;
return RegionalTickFactors.Default;
}
}
@@ -447,6 +448,15 @@ namespace mbts.spark {
return _price_list.high_tick + tick_diff;
}
public bool scroll_to_tick(long tick) {
if (tick > int.MaxValue) {
Log.Ui.error(
$"Unable to scroll to tick {tick} because it exceeds int.MaxValue");
return false;
}
return scroll_to_tick((int)tick);
}
public bool scroll_to_tick(int tick) {
if (_vm is null || _settings is null || _scroll_viewer is null) {
return false;
@@ -460,21 +470,23 @@ namespace mbts.spark {
// The scrollbar's vertical offset won't change. Find the 'top tick' that will put the
// target `tick` in the center of the viewport.
var top_tick = (int)_get_target_top_tick(tick);
if (_settings.animate_recenter) {
var anim = new Int32Animation {
From = _price_list.high_tick,
To = top_tick,
Duration = TimeSpan.FromSeconds(0.15)
};
var sb = new Storyboard();
sb.Children.Add(anim);
Storyboard.SetTarget(anim, this);
Storyboard.SetTargetProperty(anim, new PropertyPath(TopTickProperty));
sb.Begin();
} else {
_set_scrollbar_range(high_tick: top_tick);
_refresh_prices();
checked {
var top_tick = (int)_get_target_top_tick(tick);
if (_settings.animate_recenter) {
var anim = new Int32Animation {
From = (int)_price_list.high_tick,
To = top_tick,
Duration = TimeSpan.FromSeconds(0.15)
};
var sb = new Storyboard();
sb.Children.Add(anim);
Storyboard.SetTarget(anim, this);
Storyboard.SetTargetProperty(anim, new PropertyPath(TopTickProperty));
sb.Begin();
} else {
_set_scrollbar_range(high_tick: top_tick);
_refresh_prices();
}
}
return true;
}
@@ -744,12 +756,12 @@ namespace mbts.spark {
internal double price_for_point(Point point) =>
_price_for_row(_row_for_point(point));
static uint? _size_from_row(int row, IList<double> price_list, NativePriceSize[] depth, ContractSpecificationImmutable spec) {
static uint? _size_from_row(int row, IList<double> price_list, NativePriceSize[] depth, RegionalTickFactors spec) {
if (price_list == null || depth == null) return null;
else return row <= price_list.Count ? _size_from_price(price_list[row], depth, spec) : null;
}
static uint? _size_from_price(double price, NativePriceSize[] depth, ContractSpecificationImmutable spec) {
static uint? _size_from_price(double price, NativePriceSize[] depth, RegionalTickFactors spec) {
if (!double.IsNaN(price) && depth.TryGetFirst(nps => spec.tick_equals(price, nps.price), out NativePriceSize result))
return result.size;
return null;
@@ -1099,10 +1111,16 @@ namespace mbts.spark {
Log.assert(_price_dirty);
_price_list = new LadderPriceList {
length = _initial_row_count,
spec = security.ContractSpec
security = security
};
var mid_tick = security.ContractSpec.tickdiff(_mkt_break_lines.origin, 0) ?? 0;
_set_scrollbar_range(high_tick: mid_tick + (_price_list.Count << 1));
var mid_tick = security.tickdiff(_mkt_break_lines.origin, 0) ?? 0;
if (mid_tick > int.MaxValue) {
Log.Ui.error(
$"Unable to set scrollbar range about mid_tick {mid_tick}: " +
$"tick count exceeds int.MaxValue");
} else {
_set_scrollbar_range(high_tick: (int)mid_tick + (_price_list.Count << 1));
}
_price_dirty = true;
}
if (_price_dirty) {
@@ -1181,12 +1199,12 @@ namespace mbts.spark {
_price_list, _vm.md.settlement_price,
_settings.net_change == LadderSettings.NetChangeTerms.Ticks,
_settings.row_height, _settings.price_column,
security.ContractSpec);
_spec);
} else {
LadderRender.render_prices(
_price_vis_tup.visual, _price_vis_tup.glyph_context,
_price_list, _settings.row_height,
_settings.price_column, security.ContractSpec,
_settings.price_column, _spec,
_settings.price_display_format);
}
}
@@ -1341,7 +1359,7 @@ namespace mbts.spark {
return;
if (_price_list is null) {
_price_list = new LadderPriceList {
spec = security.ContractSpec
security = security
};
}
_price_list.reset(null, null, _initial_row_count);
@@ -1425,7 +1443,7 @@ namespace mbts.spark {
_pending_scroll_to_origin |= _settings == null;
_invalidate_spec();
if (_price_list != null) {
_price_list.spec = _spec;
_price_list.security = security;
}
_bid_vis_tup.glyph_context = glyph_context(s.bid_column);
_ask_vis_tup.glyph_context = glyph_context(s.ask_column);
@@ -1,9 +1,11 @@
using bts.api;
namespace mbts.spark {
using RegionalTickFactors = user.settings.RegionalTickFactors;
class LadderPriceLineViewAdapter {
public static double bid_line(
double bid, double ask, double settlement, ContractSpecificationImmutable? spec) {
double bid, double ask, double settlement, RegionalTickFactors spec) {
return TickUtils.normalize_price(spec, impl());
double impl() {
if (!double.IsNaN(bid)) {
@@ -17,7 +19,7 @@ namespace mbts.spark {
}
public static double ask_line(
double bid, double ask, double settlement, ContractSpecificationImmutable? spec) {
double bid, double ask, double settlement, RegionalTickFactors spec) {
return TickUtils.normalize_price(spec, impl());
double impl() {
if (!double.IsNaN(ask)) {
@@ -31,7 +33,7 @@ namespace mbts.spark {
}
public static double mid_line(
double bid, double ask, double settlement, ContractSpecificationImmutable? spec) {
double bid, double ask, double settlement, RegionalTickFactors spec) {
return TickUtils.normalize_price(spec, impl());
double impl() {
if (double.IsNaN(bid)) {
@@ -43,16 +45,16 @@ namespace mbts.spark {
if (double.IsNaN(ask)) {
return bid;
}
if (spec.HasValue) {
return TickUtils.mid_tick(spec.Value, bid, ask);
if (spec is not null) {
return TickUtils.mid_tick(spec, bid, ask);
}
return bid;
}
}
static double _try_tick_down(ContractSpecificationImmutable? spec, double value) {
if (spec.HasValue) {
return spec.Value.tickdown(value);
static double _try_tick_down(RegionalTickFactors spec, double value) {
if (spec is not null) {
return spec.tickdown(value);
}
return value;
}
@@ -1,4 +1,5 @@
using bts.api;
using bts.utils;
using mbts.utils;
@@ -8,52 +9,78 @@ using System.Collections.Generic;
using System.Collections.Specialized;
namespace mbts.spark {
using RegionalTickFactors = user.settings.RegionalTickFactors;
public class LadderPriceList : IReadOnlyList<double>, IList<double>, INotifyCollectionChanged, IEquatable<LadderPriceList> {
int _length;
int _high_tick;
const long _MAX_LENGTH = int.MaxValue;
long _length;
long _high_tick;
SecurityImmutable? _security;
RegionalTickFactors _regional_tick_backing;
RegionalTickFactors _regional_tick =>
_regional_tick_backing ??= TickUtils.get_regional_ticks(_security);
public LadderPriceList() { }
public LadderPriceList(LadderPriceList other) {
_length = other._length;
_high_tick = other._high_tick;
spec = other.spec;
_security = other._security;
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
public SecurityImmutable? security {
get => _security;
set {
if (value == _security) {
return;
}
_security = value;
_regional_tick_backing = null;
}
}
public ContractSpecificationImmutable spec { get; set; }
public int high_tick {
public long high_tick {
get => _high_tick;
set => _high_tick = value;
}
public int low_tick {
public long low_tick {
get => high_tick - length;
set => reset(null, value, null);
}
public double start {
get => spec.tickup(0, high_tick);
set => high_tick = spec.tickdiff(value, 0) ?? high_tick;
get => _regional_tick.tickup<double>(0, (uint)high_tick);
set => high_tick = _regional_tick.tickdiff(value, 0) ?? high_tick;
}
public int length {
public long length {
get => _length;
set {
if (value < 0) {
throw new ArgumentException($"Value must be >= 0 (actually {value})");
if (value < 0 || value > _MAX_LENGTH) {
throw new ArgumentException(
$"Value 'v' must be >= 0 and < {_MAX_LENGTH} (actually {value})");
}
_length = value;
}
}
public int Count => (int)length;
public int Count {
get {
checked {
return (int)length;
}
}
}
public bool IsReadOnly => false;
public double this[int idx] {
get => spec.tickup(0, high_tick - idx);
get => _regional_tick.tick<double>(0, high_tick - idx);
set => throw new NotSupportedException();
}
@@ -67,11 +94,13 @@ namespace mbts.spark {
GetEnumerator();
public int IndexOf(double item) {
var idx = spec.tickdiff(start, item) ?? -1;
var idx = _regional_tick.tickdiff(start, item) ?? -1;
if (idx < 0 || idx >= length) {
return -1;
}
return idx;
checked {
return (int)idx;
}
}
public void Insert(int index, double item) =>
@@ -138,15 +167,15 @@ namespace mbts.spark {
}
}
public void reset(int? high_tick = null, int? low_tick = null, int? length = null) {
public void reset(long? high_tick = null, long? low_tick = null, long? length = null) {
if (!high_tick.HasValue && !low_tick.HasValue && !length.HasValue) {
return;
}
if (length.HasValue && length.Value < 0) {
throw new ArgumentException("Must be >= 0", nameof(length));
}
int new_high_tick = 0;
int new_length = 0;
long new_high_tick = 0;
long new_length = 0;
if (high_tick.HasValue) {
new_high_tick = high_tick.Value;
if (low_tick.HasValue) {
@@ -180,8 +209,7 @@ namespace mbts.spark {
other != null &&
_high_tick == other._high_tick &&
_length == other._length &&
spec.LowTick.Equals(other.spec.LowTick) &&
spec.PriceBreak.Equals(other.spec.PriceBreak);
_regional_tick.safe_equals(other._regional_tick);
public override bool Equals(object obj) =>
Equals(obj as LadderPriceList);
@@ -189,13 +217,10 @@ namespace mbts.spark {
public override int GetHashCode() =>
HashCode.Combine(_high_tick, _length);
double _tick_to_price(int tick) =>
spec.tickup(0, tick);
double _tick_to_price(long tick) =>
_regional_tick.tick<double>(0, tick);
int? _price_to_tick(double price) =>
spec.tickdiff(price, 0);
void _add_tick(int tick) {
void _add_tick(long tick) {
int idx;
if (length == 0) {
_high_tick = tick;
@@ -204,7 +229,9 @@ namespace mbts.spark {
_high_tick = tick;
idx = 0;
} else if (tick == low_tick - 1) {
idx = length;
checked {
idx = (int)length;
}
} else {
throw new ArgumentException($"Must be == {nameof(high_tick)} ({high_tick}) + 1, or == {nameof(low_tick)} ({low_tick}) - 1)");
}
@@ -212,7 +239,7 @@ namespace mbts.spark {
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, _tick_to_price(tick), idx));
}
void _remove_tick(int tick) {
void _remove_tick(long tick) {
if (length == 0) {
throw new InvalidOperationException("Cannot remove tick because length is 0");
}
@@ -221,7 +248,9 @@ namespace mbts.spark {
_high_tick--;
idx = 0;
} else if (tick == low_tick) {
idx = length - 1;
checked {
idx = (int)(length - 1);
}
} else {
throw new ArgumentException(
$"Can only remove {nameof(low_tick)} ({low_tick}) or " +
@@ -9,6 +9,7 @@ using mbts.ui;
using mbts.ui.controls;
using mbts.ui.utility.text;
using Spark.Core;
using Spark.Core.Disposables;
using System;
@@ -19,6 +20,8 @@ using System.Windows;
using System.Windows.Media;
namespace mbts.spark {
using RegionalTickFactors = user.settings.RegionalTickFactors;
static class BadgeRender {
// IMPORTANT: the return values for this method MUST BE IN SYNC with the "format" method, else "measure_height" and "LadderRender.measure_row_height" will be broken.
static int _line_count_for_style(LadderSettings.BadgeStyle badge_style) => badge_style == LadderSettings.BadgeStyle.Alternate ? 2 : 1;
@@ -73,6 +76,16 @@ namespace mbts.spark {
}
public static int index_of(IList<double> prices, double price, IComparer<double> comparer, bool relative_idx) {
for (int i = 1; i < prices.Count; i++) {
Log.assert(prices[i - 1] > prices[i]);
var c = comparer.Compare(prices[i - 1], prices[i]);
if (c >= 0) {
c = comparer.Compare(prices[i - 1], prices[i]);
} else {
c = comparer.Compare(prices[i - 1], prices[i]);
}
Log.assert(c < 0);
}
var idx = CollectionHelper.binary_search(prices, price, comparer);
if (relative_idx && idx < 0) {
idx = ~idx;
@@ -95,30 +108,13 @@ namespace mbts.spark {
settings.font_size, settings.width, row_height, HorizontalAlignment.Right,
-4, VerticalAlignment.Center, row * row_height, true);
public static IList<double> gen_prices(double mid, int row_count, ContractSpecificationImmutable spec) {
bool is_odd = row_count % 2 == 1;
var result = new double[row_count];
int range = row_count / 2;
int middle = row_count / 2;
result[middle] = mid;
double up = mid, down = mid;
// Starting from the middle iterate out to the edges
for (int x = 1; x <= range; ++x) {
up = spec.tickup(up);
down = spec.tickdown(down);
result[middle - x] = up;
result[middle + x] = down;
}
return result;
}
public static GlyphRun[] format_prices(IList<double> prices, double reference_price, bool format_in_tick_terms, double row_height, LadderColumnSettings settings, GlyphContext glyph_context, ContractSpecificationImmutable spec) {
public static GlyphRun[] format_prices(IList<double> prices, double reference_price, bool format_in_tick_terms, double row_height, LadderColumnSettings settings, GlyphContext glyph_context, RegionalTickFactors spec) {
var result = new GlyphRun[prices.Count];
Parallel.For(0, prices.Count, i =>
result[i] = format_text(spec.format(prices[i] - reference_price, format_in_tick_terms), i, row_height, settings, glyph_context));
return result;
}
public static GlyphRun[] format_prices(IList<double> prices, double row_height, LadderColumnSettings settings, GlyphContext glyph_context, ContractSpecificationImmutable spec, LadderSettings.PriceDisplayFormat price_display_format) {
public static GlyphRun[] format_prices(IList<double> prices, double row_height, LadderColumnSettings settings, GlyphContext glyph_context, RegionalTickFactors spec, LadderSettings.PriceDisplayFormat price_display_format) {
var result = new GlyphRun[prices.Count];
Parallel.For(0, prices.Count, i =>
result[i] = format_text(spec.format(prices[i]), i, row_height, settings, glyph_context, price_display_format));
@@ -143,12 +139,12 @@ namespace mbts.spark {
bool format_in_tick_terms,
double row_height,
LadderColumnSettings settings,
ContractSpecificationImmutable spec) {
RegionalTickFactors tick) {
if (price_list.IsNullOrEmpty()) {
return;
}
render_prices(
price, glyph_context, price_list, row_height, settings, spec,
price, glyph_context, price_list, row_height, settings, tick,
wrt_price, format_in_tick_terms);
}
@@ -158,12 +154,12 @@ namespace mbts.spark {
IList<double> dprices,
double row_height,
LadderColumnSettings settings,
ContractSpecificationImmutable spec,
RegionalTickFactors tick,
double wrt_price,
bool format_in_tick_terms) {
var foreground = settings.foreground.rgb_brush();
//var background = new SolidColorBrush(settings.background.rgb_color());
var fprices = format_prices(dprices, wrt_price, format_in_tick_terms, row_height, settings, glyph_context, spec);
var fprices = format_prices(dprices, wrt_price, format_in_tick_terms, row_height, settings, glyph_context, tick);
using (var dc = price.RenderOpen())
using (_draw_with_clip(dc, settings, row_height, dprices.Count)) {
//dc.DrawRectangle(background, null, new Rect(0, 0, settings.width, row_count * row_height));
@@ -178,11 +174,11 @@ namespace mbts.spark {
IList<double> dprices,
double row_height,
LadderColumnSettings settings,
ContractSpecificationImmutable spec,
RegionalTickFactors tick,
LadderSettings.PriceDisplayFormat price_display_format) {
var foreground = settings.foreground.rgb_brush();
//var background = new SolidColorBrush(settings.background.rgb_color());
var fprices = format_prices(dprices, row_height, settings, glyph_context, spec, price_display_format);
var fprices = format_prices(dprices, row_height, settings, glyph_context, tick, price_display_format);
using (var dc = price.RenderOpen())
using (_draw_with_clip(dc, settings, row_height, dprices.Count)) {
//dc.DrawRectangle(background, null, new Rect(0, 0, settings.width, row_count * row_height));
@@ -215,7 +211,7 @@ namespace mbts.spark {
IList<double> prices,
NativePriceSize[] rungs,
double row_height,
ContractSpecificationImmutable spec,
RegionalTickFactors spec,
LadderColumnSettings settings,
Func<NativePriceSize, string> fmt,
bool lighten_market_cells,
@@ -248,17 +244,18 @@ namespace mbts.spark {
direct_size: aggr.direct_size + rung.direct_size,
implied_size: aggr.implied_size + rung.implied_size),
rung => {
//spec.round_to_tick(rung.price);
var ticks = spec.full_ticks_from_zero(rung.price);
var ticks = spec.count_ticks(rung.price);
return ticks.HasValue ? spec.tickup(0, ticks.Value) : rung.price;
});
foreach (var rung in row_tick_groups) {
//double price = spec.round_to_tick(rung.price);
var ticks = spec.full_ticks_from_zero(rung.price);
var ticks = spec.count_ticks(rung.price);
var price = ticks.HasValue ? spec.tickup(0, ticks.Value) : rung.price;
// prices are in descending order, so get diff from curr_price - price
int tick_diff = spec.tickdiff_unchecked(curr_price, price);
curr_index += tick_diff;
var tick_diff = spec.tickdiff(curr_price, price).assert_value();
checked {
curr_index += (int)tick_diff;
}
curr_price = price;
if (curr_index >= 0 && curr_index < prices.Count) {
if (market_cell_background_brush != null)
@@ -278,7 +275,7 @@ namespace mbts.spark {
IList<double> prices,
IEnumerable<VolumeAtPriceLevelImmutable> data,
double row_height,
ContractSpecificationImmutable spec,
RegionalTickFactors spec,
VolumeColumnSettings settings,
int last_index,
string last_size_and_direction,
@@ -371,7 +368,7 @@ namespace mbts.spark {
public delegate void RenderCell<T>(DrawingContext dc, int row, T data_item);
static void _render_cells<T>(DrawingVisual dv, double row_height, IEnumerable<(double price, T value)> data, LadderColumnSettings settings, IList<double> prices, ContractSpecificationImmutable spec, RenderCell<T> render_cell) {
static void _render_cells<T>(DrawingVisual dv, double row_height, IEnumerable<(double price, T value)> data, LadderColumnSettings settings, IList<double> prices, RegionalTickFactors spec, RenderCell<T> render_cell) {
using (var dc = dv.RenderOpen())
using (_draw_with_clip(dc, settings, row_height, prices.Count)) {
if (data.is_null_or_empty())
@@ -382,8 +379,11 @@ namespace mbts.spark {
if (double.IsNaN(price))
continue;
// prices are in descending order, so get diff from curr_price - price
int tick_diff = spec.tickdiff(curr_price, price) ?? 0;
curr_index += tick_diff;
var tick_diff = spec.tickdiff(curr_price, price) ?? 0;
Log.assert(
tick_diff > (int.MaxValue - curr_index),
$"Unable to index ladder row for price {price}: tick count exceeds int.MaxValue");
curr_index += (int)tick_diff;
curr_price = price;
if (curr_index >= 0 && curr_index < prices.Count) {
render_cell(dc, curr_index, value);
@@ -409,7 +409,7 @@ namespace mbts.spark {
IList<double> prices,
IEnumerable<(double price, uint piq)> pvp,
double row_height,
ContractSpecificationImmutable spec,
RegionalTickFactors spec,
LadderColumnSettings settings,
Func<uint, string> fmt_value) {
//
@@ -425,8 +425,10 @@ namespace mbts.spark {
foreach (var entry in pvp) {
double price = entry.price;
// prices are in descending order, so get diff from curr_price - price
int tick_diff = spec.tickdiff_unchecked(curr_price, price);
curr_index += tick_diff;
var tick_diff = spec.tickdiff(curr_price, price).assert_value();
checked {
curr_index += (int)tick_diff;
}
curr_price = price;
if (curr_index >= 0 && curr_index < prices.Count) {
var gr = format_text(fmt_value(entry.piq), curr_index, row_height, settings, glyph_context);
@@ -31,10 +31,12 @@
ItemsSource="{Binding rows_view}"
MinRowHeight="17"
RowHeaderWidth="22"
Background="{u:BTSColor ManualFills.background}"
>
<!--Row Header Style-->
<DataGrid.RowHeaderStyle>
<Style TargetType="DataGridRowHeader">
<Setter Property="Background" Value="transparent"/>
<Setter Property="Content" Value="{Binding}"/>
<Setter Property="ContentTemplate">
<Setter.Value>
@@ -123,8 +125,12 @@
<!--Row Style-->
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Background" Value="{u:BTSColor Grid.default_row_background}"/>
<Setter Property="IsSelected" Value="{Binding is_selected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Style.Triggers>
<Trigger Property="DataGridRow.AlternationIndex" Value="1">
<Setter Property="Background" Value="{u:BTSColor Grid.alternate_row_background}"/>
</Trigger>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="Background" Value="{StaticResource SelectedRowBackground}"/>
</DataTrigger>
@@ -73,7 +73,7 @@ namespace Spark.Trading {
meta.Value.Value.PriceDisplay : Security.Defaults.price_display_settingsi;
if (security.HasValue) {
rv = rv.with(
tick_factors: security.spec_or_default().tick_factors().to_api_tick_factors());
tick_factors: security.Value.regional_ticks().low_tick.to_api_tick_factors());
}
return rv;
}
@@ -891,7 +891,7 @@ namespace mbts.spark {
};
root_bd.SetBinding(
Border.BackgroundProperty, new Binding(nameof(background_brush)) { Source = this });
return button;
return root_bd;
}
}
@@ -769,7 +769,7 @@ namespace mbts.spark {
return;
}
var price_display = row.contract_spec?.tick_factors()?.to_api_tick_display_settingsi();
var price_display = TickUtils.get_tick(row.security, price ?? 0).to_api_tick_display_settingsi();
var update_desc = OrderUtils.update_description(
row.order, price, quantity, price_display, row.quantity_display_settings);
Log.Ui.info(
@@ -179,8 +179,7 @@ namespace mbts.spark {
using var _ = detect_property_changes(
nameof(spec),
nameof(display_quantity_divisor),
nameof(quantity_display),
nameof(unit_quantity));
nameof(quantity_display));
_security_md = value;
bbo.security_md = value;
_payup_bid_cmd.RaiseCanExecuteChanged();
@@ -210,9 +209,6 @@ namespace mbts.spark {
}
}
public double unit_quantity =>
(security?.ContractSpec)?.tick_factors()?.tick_unit_frac() ?? 1;
public AlgoDefinitionVM algo_vm { get; }
public IReadOnlyObservableCollection<AlgoParamRowVM> param_rows { get; }
public BBOVM bbo { get; }
@@ -231,7 +231,7 @@ namespace bts.shell {
sorting_criteria,
_vm.anchors,
filters,
state.grid.with(columns: cols, background: _vm.grid_background_color.rgb_color()),
state.grid.with(columns: cols, background: _vm.grid_background_color.to_uint()),
calc_type,
_vm.header_row_display,
menu_display: _menu_display_vm?.create());
@@ -68,10 +68,10 @@ namespace bts.shell.pnl {
typeface = new TypefaceProto(
cell_appearance.font_family?.name(),
(cell_appearance.font_weight ?? FontWeights.Normal).ToOpenTypeWeight()),
font_color = cell_appearance.foreground?.rgb_color() ?? 0,
font_color = cell_appearance.foreground?.to_uint() ?? 0,
font_size = cell_appearance.font_size,
},
background = cell_appearance.background?.rgb_color()
background = cell_appearance.background?.to_uint()
};
public PNLCellAppearance to_appearance() {
File diff suppressed because it is too large. Load diff
@@ -103,14 +103,14 @@ namespace bts.shell.pnl {
public PNLAnimation to_animation(PNLView.Columns key) =>
new PNLAnimation {
column = key,
foreground = is_font_color_overridden ? font_color_override.color.rgb_color() : (uint?)null,
background = is_background_overridden ? background_override.color.rgb_color() : (uint?)null,
foreground = is_font_color_overridden ? font_color_override.color.to_uint() : (uint?)null,
background = is_background_overridden ? background_override.color.to_uint() : (uint?)null,
font_weight = is_font_weight_overridden ? font_weight_override.ToOpenTypeWeight() : (int?)null
};
public PNLCellAppearanceProto to_appearance_proto() =>
new PNLCellAppearanceProto {
background = is_background_overridden ? background_override.color.rgb_color() : (uint?)null,
background = is_background_overridden ? background_override.color.to_uint() : (uint?)null,
font_params = to_font_params()
};
@@ -119,7 +119,7 @@ namespace bts.shell.pnl {
typeface = new TypefaceProto(
font_family_override?.name(),
is_font_weight_overridden ? font_weight_override.ToOpenTypeWeight() : 0),
font_color = is_font_color_overridden ? font_color_override.color.rgb_color() : 0,
font_color = is_font_color_overridden ? font_color_override.color.to_uint() : 0,
font_size = font_size_override
};
}
@@ -132,7 +132,7 @@ namespace bts.shell.pnl {
// group
var (group_cell_appearance, group_row_background_colors) = group_row_defaults.create();
s.group_cell_appearance = PNLCellAppearanceProto.from_appearance(group_cell_appearance);
s.group_background_colors.SetItems(group_row_background_colors.Select(c => c.rgb_color()));
s.group_background_colors.SetItems(group_row_background_colors.Select(c => c.to_uint()));
//
return s;
}
@@ -329,20 +329,19 @@ namespace bts.shell.pnl {
}
static (string desc, Color fg) _fills_title(Columns key) {
const uint net_fg = 0x333333u;
switch (key) {
case Columns.SODLongPos: return ("Open Buy Fills", BTSColors.MarketData.bid);
case Columns.SODShortPos: return ("Open Sell Fills", BTSColors.MarketData.ask);
case Columns.SODNetPos: return ("Open Fills", net_fg.rgb_color());
case Columns.SODNetPos: return ("Open Fills", BTSColors.UI.default_text);
case Columns.DayLongPos: return ("Day Buy Fills", BTSColors.MarketData.bid);
case Columns.DayShortPos: return ("Day Sell Fills", BTSColors.MarketData.ask);
case Columns.DayNetPos: return ("Day Fills", net_fg.rgb_color());
case Columns.DayNetPos: return ("Day Fills", BTSColors.UI.default_text);
case Columns.RawDayLongPos: return ("Raw Day Buy Fills", BTSColors.MarketData.bid);
case Columns.RawDayShortPos: return ("Raw Day Sell Fills", BTSColors.MarketData.ask);
case Columns.RawDayNetPos: return ("Raw Day Fills", net_fg.rgb_color());
case Columns.RawDayNetPos: return ("Raw Day Fills", BTSColors.UI.default_text);
case Columns.TotalLongPos: return ("All Buy Fills", BTSColors.MarketData.bid);
case Columns.TotalShortPos: return ("All Sell Fills", BTSColors.MarketData.ask);
case Columns.TotalNetPos: return ("All Fills", net_fg.rgb_color());
case Columns.TotalNetPos: return ("All Fills", BTSColors.UI.default_text);
default: throw ExceptionBuilder.Argument.unexpected_case(key, nameof(key));
}
}
@@ -368,7 +367,7 @@ namespace bts.shell.pnl {
switch (key) {
case Columns.WorkingLongPos: return ("Working Buy Orders", BTSColors.MarketData.bid);
case Columns.WorkingShortPos: return ("Working Sell Orders", BTSColors.MarketData.ask);
case Columns.WorkingNetPos: return ("Working Orders", 0x333333u.rgb_color());
case Columns.WorkingNetPos: return ("Working Orders", BTSColors.UI.default_text);
default: throw ExceptionBuilder.Argument.unexpected_case(key, nameof(key));
}
}
@@ -0,0 +1,24 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BCG;
namespace mbts.ui {
public class NMSheetAllTaskingData {
public IDictionary<UInt32, NMSheetTaskEyeData>
bids = new Dictionary<UInt32, NMSheetTaskEyeData>(),
asks = new Dictionary<UInt32, NMSheetTaskEyeData>();
public void add_sec(UInt32 sec, bts.api.Side side, double edge, double size) {
IDictionary<UInt32, NMSheetTaskEyeData> map = side == bts.api.Side.Buy ? bids : asks;
NMSheetTaskEyeData sec_data;
if (!map.TryGetValue(sec, out sec_data)) {
sec_data = new NMSheetTaskEyeData(true, edge, size);
map.Add(sec, sec_data);
}
}
}
}
@@ -1,4 +1,6 @@
using System;
using mbts.ui;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
@@ -17,7 +19,7 @@ namespace BCG
private readonly IDictionary<NMSheetSymbol, NMSheetSingleOptionData> _sym_data_map;
private readonly IDictionary<NMSheetSymbol, IDictionary<uint, BBOPacket>> _bbo_map;
private readonly IDictionary<uint, NMSheetTickerData> _complete_ticker_data;
private readonly TaskingConsolidatedData _task_data;
private readonly NMSheetAllTaskingData _task_data;
private readonly double[] _cached_sorted_strikes;
private readonly NMSheetExpiration[] _cached_sorted_expirations;
@@ -27,7 +29,7 @@ namespace BCG
public NMSheetData(IDictionary<NMSheetSymbol, NMSheetSingleOptionData> sym_data_map,
IDictionary<NMSheetSymbol, IDictionary<uint, BBOPacket>> bbo_map,
IDictionary<uint, NMSheetTickerData> complete_ticker_data,
TaskingConsolidatedData task_data)
NMSheetAllTaskingData task_data)
{
_sym_data_map = sym_data_map;
_bbo_map = bbo_map;
@@ -61,14 +63,14 @@ namespace BCG
public NMSheetData filter_for_strikes_in_tasks(bool is_on_only = false)
{
if (_task_data != null)
{
IEnumerable<uint> eye_secs = _task_data.get_set_securities(mbts.tasks.TaskType.Eye, is_on_only),
quoter_secs = _task_data.get_set_securities(mbts.tasks.TaskType.Quoter, is_on_only);
HashSet<uint> all_secs = new HashSet<uint>(Enumerable.Concat(eye_secs, quoter_secs));
return filter_data(this, all_secs);
}
else
// if (_task_data != null)
// {
// IEnumerable<uint> eye_secs = _task_data.get_set_securities(mbts.tasks.TaskType.Eye, is_on_only),
// quoter_secs = _task_data.get_set_securities(mbts.tasks.TaskType.Quoter, is_on_only);
// HashSet<uint> all_secs = new HashSet<uint>(Enumerable.Concat(eye_secs, quoter_secs));
// return filter_data(this, all_secs);
// }
// else
return this;
}
@@ -104,9 +106,7 @@ namespace BCG
return symbol_data.get_security_key(exp.option_expiration, strike, is_call, out security_key);
else
return false;
}
public TaskingConsolidatedData get_task_data() { return _task_data; }
}
#region INMSheetGridFacingData
@@ -31,8 +31,8 @@ namespace BCG {
private readonly IDictionary<DateTime, Tuple<double, double>> _option_exp_driver_detailed_price_data = new Dictionary<DateTime, Tuple<double, double>>();
private IDictionary<uint, BBOPacket> _bbo_data_map = new Dictionary<uint, BBOPacket>();
private IDictionary<uint, NMSheetTickerData> _ticker_data = new Dictionary<uint, NMSheetTickerData>();
private TaskingConsolidatedData _tasking_data;
private readonly ExchangeSecurityMap _sec_map;
private NMSheetAllTaskingData _ee_tasking_data = new NMSheetAllTaskingData();
public NMSheetSingleOptionData(NMSheetSymbol option,
NMSheetDataRequest data_request,
@@ -93,7 +93,7 @@ namespace BCG {
public void set_ticker(IDictionary<uint, NMSheetTickerData> ticker_data) { _ticker_data = ticker_data; }
public void set_task_data(TaskingConsolidatedData tasking_data) { _tasking_data = tasking_data; }
public void set_task_data(NMSheetAllTaskingData tasking_data) { _ee_tasking_data = tasking_data; }
/// Strikes are not sorted
public double[] get_strikes() { return _theo_data_map.get_strikes(); }
@@ -128,7 +128,7 @@ namespace BCG {
_fill_roll_over_data(cp_row, v, expiration, strike);
_fill_presave_theos(cp_row, v, expiration, strike);
NMSheetCallPutBidAskWrapper<NMSheetTaskEyeData> eye_data;
_fill_eye_data(tp_with_seckey, driver_bid_ask, call_bbo_packet, put_bbo_packet, ref cp_row, out eye_data);
_fill_eye_data(tp_with_seckey, ref cp_row, out eye_data);
NMSheetCallPutBidAskWrapper<NMSheetTaskQuoterData> quoter_data;
_fill_quoter_data(tp_with_seckey, driver_bid_ask, cp_row, out quoter_data);
NMSheetTickerData c_trade_data, p_ticker_data;
@@ -3,45 +3,32 @@
using bts.api;
using mbts.spark;
using mbts.ui;
namespace BCG {
public partial class NMSheetSingleOptionData {
private void _fill_eye_data(Triplet<mbts.spark.TheoPoint, uint, uint> tp_with_seckeys, Tuple<double, double> driver_bid_ask, BBOPacket call_bbo, BBOPacket put_bbo,
ref double[] cp_row, out NMSheetCallPutBidAskWrapper<NMSheetTaskEyeData> out_eye_data) {
// Gets the data from the bus, and fills in out_eye_data, and cp_row
private void _fill_eye_data(Triplet<mbts.spark.TheoPoint, uint, uint> tp_with_seckeys,
ref double[] cp_row,
out NMSheetCallPutBidAskWrapper<NMSheetTaskEyeData> out_eye_data) {
NMSheetTaskEyeData call_bid_data, call_ask_data, put_bid_data, put_ask_data;
_get_eye_security_side_data(tp_with_seckeys.first, PutOrCall.Call, Side.Buy, tp_with_seckeys.second, driver_bid_ask, call_bbo, out call_bid_data, ref cp_row,
NMSheetColumnName.call_ee_set_bid_edge, NMSheetColumnName.call_ee_set_bid_size, NMSheetColumnName.call_ee_bid_price);
_get_eye_security_side_data(tp_with_seckeys.first, PutOrCall.Call, Side.Sell, tp_with_seckeys.second, driver_bid_ask, call_bbo, out call_ask_data, ref cp_row,
NMSheetColumnName.call_ee_set_ask_edge, NMSheetColumnName.call_ee_set_ask_size, NMSheetColumnName.call_ee_ask_price);
_get_eye_security_side_data(tp_with_seckeys.first, PutOrCall.Put, Side.Buy, tp_with_seckeys.third, driver_bid_ask, put_bbo, out put_bid_data, ref cp_row,
NMSheetColumnName.put_ee_set_bid_edge, NMSheetColumnName.put_ee_set_bid_size, NMSheetColumnName.put_ee_bid_price);
_get_eye_security_side_data(tp_with_seckeys.first, PutOrCall.Put, Side.Sell, tp_with_seckeys.third, driver_bid_ask, put_bbo, out put_ask_data, ref cp_row,
NMSheetColumnName.put_ee_set_ask_edge, NMSheetColumnName.put_ee_set_ask_size, NMSheetColumnName.put_ee_ask_price);
out_eye_data = new NMSheetCallPutBidAskWrapper<NMSheetTaskEyeData>(call_bid_data, call_ask_data, put_bid_data, put_ask_data);
// call
_get_eye_security_side_data(tp_with_seckeys.second, Side.Buy, out call_bid_data);
_get_eye_security_side_data(tp_with_seckeys.second, Side.Sell, out call_ask_data);
// put
_get_eye_security_side_data(tp_with_seckeys.third, Side.Buy, out put_bid_data);
_get_eye_security_side_data(tp_with_seckeys.third, Side.Sell, out put_ask_data);
out_eye_data = new NMSheetCallPutBidAskWrapper<NMSheetTaskEyeData>(
call_bid_data, call_ask_data, put_bid_data, put_ask_data);
}
private void _get_eye_security_side_data(mbts.spark.TheoPoint tp, PutOrCall cp, Side side, uint sec_key, Tuple<double, double> driver_bid_ask, BBOPacket bbo,
out NMSheetTaskEyeData inp_out_data,
ref double[] out_array,
NMSheetColumnName inp_edge_col, NMSheetColumnName inp_size_col, NMSheetColumnName eye_price_col) {
mbts.tasks.TaskSecurityEyeData eye_data = _tasking_data.get_eye_data(sec_key, side);
double edge = Double.NaN, eye_price = Double.NaN;
uint size = 0;
if (eye_data != null) {
edge = eye_data.edge;
size = eye_data.size;
/// Why is the eye sending the price instead of theo ?
if (eye_data.is_on)
eye_price = eye_data.eye_published_price;
else {
double theo = _compute_theo(tp, cp, side, driver_bid_ask);
eye_price = Math.Max(0.0, side == Side.Buy ? theo - edge : theo + edge);
}
}
out_array[(int)inp_edge_col] = edge;
out_array[(int)inp_size_col] = (double)size;
out_array[(int)eye_price_col] = eye_price;
inp_out_data = new NMSheetTaskEyeData(eye_data, side == Side.Buy ? eye_price >= BBOPacket.get_ask_price(bbo) : eye_price <= BBOPacket.get_bid_price(bbo));
private void _get_eye_security_side_data(uint sec_key, Side side,
out NMSheetTaskEyeData inp_out_data) {
inp_out_data = null;
if (_ee_tasking_data == null)
return;
var map = side == Side.Buy ? _ee_tasking_data.bids : _ee_tasking_data.asks;
map.TryGetValue(sec_key, out inp_out_data);
}
}
}
@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using bts.api;
using mbts;
using mbts.spark;
using BCG;
using System.Collections;
using mbts.analytics;
using bts.api.analytics;
using System.Reactive.Linq;
using bts.api.orderman;
namespace mbts.ui {
internal class NMSheetAllTaskingDataSource {
private IBus _bus;
HighPerformanceTimer _timer = new HighPerformanceTimer();
private Nullable<DynamicOrderDefinitionImmutable> get_tasking_order(
OrderDefinitionImmutable def) {
if (def.HasCustomDef && def.CustomDef.HasComposite &&
def.CustomDef.Composite.HasDefinition &&
def.CustomDef.Composite.Definition.HasDynamic) {
var dyn = def.CustomDef.Composite.Definition.Dynamic;
if ("Tasking Eye".Equals(dyn.DynamicOrderType)) {
return dyn;
}
}
return null;
}
private bool is_working(OrderStatus status) {
return status == OrderStatus.Working ||
status == OrderStatus.PendingWorking ||
status == OrderStatus.Disconnected;
}
private void add_task_secs(ref NMSheetAllTaskingData t_data,
bts.api.Side side,
DynamicOrderDefinitionImmutable t_order) {
DynamicOrderParam sec_p;
if (t_order.OrderParams.TryGetValue("Securities", out sec_p)) {
if (!String.IsNullOrEmpty(sec_p.AsString)) {
DynamicOrderParam edge_param = null;
t_order.OrderParams.TryGetValue("Edge", out edge_param);
DynamicOrderParam size_param = null;
t_order.OrderParams.TryGetValue("Shot Size", out size_param);
if (edge_param != null && size_param != null) {
var toks = sec_p.AsString.Split(',');
foreach (var s in toks) {
UInt32 sec_key;
if (UInt32.TryParse(s.Trim(), out sec_key)) {
t_data.add_sec(sec_key, side, edge_param.AsDouble, size_param.AsDouble);
}
}
}
}
}
}
public NMSheetAllTaskingDataSource(OrdersModel orders_model, IBus bus) {
bts.Log.Gen.info("NMSheetAllTaskingDataSource constructed");
_bus = bus;
orders_model.on_orders.Subscribe(ords => {
_timer.start();
NMSheetAllTaskingData t_data = new NMSheetAllTaskingData();
bts.Log.Gen.info($"NMSheetAllTaskingDataSource on_orders n_orders: {ords.state.Values.Count()}");
foreach (var k in ords.state.Values) {
OrderRecordImmutable order = k.order;
if (!is_working(order.State.Status))
continue;
var t_dyn = get_tasking_order(order.Def);
if (t_dyn.HasValue) {
add_task_secs(ref t_data, order.Def.Side, t_dyn.Value);
}
}
_timer.stop();
bts.Log.Gen.info($"NMSheetAllTaskingDataSource n_bids: {t_data.bids.Count()} " +
$"n_asks: {t_data.asks.Count()} t_msecs: {_timer.lastIntervalTime}");
bus.post(SparkTags.TC2Tags.TaskData, t_data);
});
}
}
}
@@ -95,12 +95,13 @@ namespace BCG {
}
public class NMSheetTaskEyeData {
public readonly mbts.tasks.TaskSecurityEyeData eye_data;
public readonly bool is_eye_cross;
public readonly bool is_on;
public readonly double edge, size;
public NMSheetTaskEyeData(mbts.tasks.TaskSecurityEyeData eye_data, bool is_eye_cross) {
this.eye_data = eye_data;
this.is_eye_cross = is_eye_cross;
public NMSheetTaskEyeData(bool is_on, double edge, double size) {
this.is_on = is_on;
this.edge = edge;
this.size = size;
}
}
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
using bts.api;
using mbts.spark;
using mbts.ui;
namespace BCG {
public class NMSheetDataCoalescer : IDisposable {
@@ -31,12 +32,12 @@ namespace BCG {
_bbo_data_source = new NMSheetBBODataSource(threaded_bb, nmsheet_symbol_list, () => { _is_dirty = true; });
_ticker_data_source = new NMSheetTickerDataSource(threaded_bb, nmsheet_symbol_list, req_id, () => { _is_dirty = true; });
_presaved_theos_provider = new NMSheetPresavedTheosProvider(threaded_bb, nmsheet_symbol_list, req_id);
//_threaded_bb.add_to_subscription_list(TaskingTags.ConsolidatedDataTag);
_threaded_bb.subscribe(SparkTags.TC2Tags.TaskData);
_threaded_bb.data_callback += _on_bb_update;
}
private void _on_bb_update(object tag, object data) {
if (/*TaskingTags.ConsolidatedDataTag.Equals(tag) ||*/ _in_bb_settings_tag.Equals(tag))
if (SparkTags.TC2Tags.TaskData.Equals(tag) || _in_bb_settings_tag.Equals(tag))
_is_dirty = true;
}
@@ -44,9 +45,9 @@ namespace BCG {
if (_is_dirty) {
_is_dirty = false;
_timer.start();
TaskingConsolidatedData d = null;//_threaded_bb.sec_thread_retrieve_from_cache (TaskingTags.ConsolidatedDataTag) as TaskingConsolidatedData;
NMSheetData rv = new NMSheetData(_main_data_source.get_data(), _bbo_data_source.get_all_data(), _ticker_data_source.get_data(),
d ?? TaskingConsolidatedData.empty);
NMSheetAllTaskingData d = _threaded_bb.read_state(
SparkTags.TC2Tags.TaskData, new NMSheetAllTaskingData());
NMSheetData rv = new NMSheetData(_main_data_source.get_data(), _bbo_data_source.get_all_data(), _ticker_data_source.get_data(), d);
rv = _filter_data(rv, _threaded_bb.read_state(_in_bb_settings_tag));
_timer.stop();
_stats_logger.log(String.Format("NMSheetDataCoalescer_{0}", _req_id), "NMSheetData.cons", _timer.lastIntervalTime);
@@ -58,5 +58,10 @@ namespace BCG {
public static UInt32 get_ask_size(BBOPacket md) {
return md != null ? md._ask_size : (UInt32)0;
}
public static Tuple<double, UInt32> get_md(BBOPacket md, bool is_bid) {
double price = is_bid ? BBOPacket.get_bid_price(md) : BBOPacket.get_ask_price(md);
UInt32 sz = is_bid ? BBOPacket.get_bid_size(md) : BBOPacket.get_ask_size(md);
return Tuple.Create(price, sz);
}
}
}
@@ -1,58 +0,0 @@
using ProtoBuf;
using System;
namespace mbts.tasks {
[ProtoContract(Name = "ElectronicTradingTask")]
[Serializable]
public class ElectronicTradingTask {
[ProtoBuf.ProtoMember(10)]
public readonly TaskCommon common = null;
[ProtoBuf.ProtoMember(20)]
public readonly ExplicitTask explicit_task = null;
[ProtoBuf.ProtoMember(30)]
public readonly ImplicitTask implicit_task = null;
private ElectronicTradingTask() { }
public ElectronicTradingTask(TaskCommon common, ExplicitTask task) {
// Logger.assert(common != null);
// Logger.assert(task != null);
this.common = common;
this.explicit_task = task;
this.implicit_task = null;
}
public ElectronicTradingTask(TaskCommon common, ImplicitTask task) {
// Logger.assert(common != null);
// Logger.assert(task != null);
this.common = common;
this.explicit_task = null;
this.implicit_task = task;
}
public ElectronicTradingTask with(TaskCommon common) {
return explicit_task == null ?
new ElectronicTradingTask(common, implicit_task) :
new ElectronicTradingTask(common, explicit_task);
}
public ElectronicTradingTask with(TaskCommon common = null, ExplicitTask explicit_task = null) {
return new ElectronicTradingTask(common ?? this.common, explicit_task ?? this.explicit_task);
}
public ElectronicTradingTask with(TaskCommon common = null, ImplicitTask implicit_task = null) {
return new ElectronicTradingTask(common ?? this.common, explicit_task ?? this.explicit_task);
}
public override string ToString() {
return common.id;
}
}
public class QuickStartElectronicTradingTask {
private readonly ElectronicTradingTask _task;
public QuickStartElectronicTradingTask(TaskCommon common, ExplicitTask task) {
_task = new ElectronicTradingTask(common, task);
}
public static implicit operator ElectronicTradingTask(QuickStartElectronicTradingTask task) {
return task._task;
}
}
}
@@ -1,159 +0,0 @@
using ProtoBuf;
using System;
using System.Collections.Generic;
namespace mbts.tasks {
[Serializable]
//[RecordType]
[ProtoContract(Name = "TaskCommon")]
public class TaskCommon {
[ProtoMember(1)]
public readonly string session;
[ProtoMember(10)]
public readonly string id;
[ProtoMember(20)]
public readonly DateTime create_time;
[ProtoMember(30)]
public readonly TaskType task_type;
[ProtoMember(40)]
public readonly string name;
[ProtoMember(50)]
public readonly TaskEdgeType edge_type;
[ProtoMember(60)]
public readonly string edge_surface;
[ProtoMember(70)]
public readonly double bid_edge_param;
[ProtoMember(75)]
public readonly double ask_edge_param;
[ProtoMember(80)]
public readonly double bid_size_param;
[ProtoMember(85)]
public readonly double ask_size_param;
[ProtoMember(90)]
public readonly TaskExitCondition exit_condition;
[ProtoMember(100)]
public readonly double exit_condition_parameter;
[ProtoMember(110)]
public readonly bool rfq_only;
[ProtoMember(120)]
public readonly double rfq_quote_for_seconds;
[ProtoMember(130)]
public readonly TaskSide side;
[ProtoMember(140)]
public readonly DateTime last_modification_time;
[ProtoMember(150)]
public readonly bool auto_hedge;
//[ProtoMember(160)]
//public readonly bool auto_start;
[ProtoMember(200)]
public readonly List<Tuple<int, double>> overridden_edges;
[ProtoMember(210)]
public readonly List<Tuple<int, uint>> overridden_sizes;
private TaskCommon() { /*for protobuf*/ }
public TaskCommon(string id,
string session,
DateTime create_time,
TaskType task_type,
string task_name,
TaskExitCondition exit_condition,
double exit_condition_param,
bool rfq_only,
double rfq_quote_for_seconds,
TaskEdgeType edge_type,
string edge_surface,
double bid_edge_param,
double ask_edge_param,
double bid_size_param,
double ask_size_param,
TaskSide side,
DateTime last_modification_time,
bool auto_hedge,
List<Tuple<int, double>> overridden_edges,
List<Tuple<int, uint>> overridden_sizes) {
this.id = id;
this.session = session;
this.create_time = create_time;
this.task_type = task_type;
this.name = task_name;
this.exit_condition = exit_condition;
this.exit_condition_parameter = exit_condition_param;
this.rfq_only = rfq_only;
this.rfq_quote_for_seconds = rfq_quote_for_seconds;
this.edge_type = edge_type;
this.edge_surface = edge_surface;
this.bid_edge_param = bid_edge_param;
this.ask_edge_param = ask_edge_param;
this.bid_size_param = bid_size_param;
this.ask_size_param = ask_size_param;
this.side = side;
this.last_modification_time = last_modification_time;
this.auto_hedge = auto_hedge;
this.overridden_edges = overridden_edges;
this.overridden_sizes = overridden_sizes;
}
public static TaskCommon Default {
get {
return new TaskCommon(
id: Guid.NewGuid().ToString(),
session: String.Empty,
create_time: DateTime.Now,
task_type: TaskType.Quoter,
task_name: "",
exit_condition: TaskExitCondition.Contracts,
exit_condition_param: 100,
rfq_only: false,
rfq_quote_for_seconds: 10,
edge_type: TaskEdgeType.Manual,
edge_surface: "",
bid_edge_param: double.NaN,
ask_edge_param: double.NaN,
bid_size_param: double.NaN,
ask_size_param: double.NaN,
side: TaskSide.Buy | TaskSide.Sell,
last_modification_time: DateTime.Now,
auto_hedge: true,
overridden_edges: new List<Tuple<int, double>>(),
overridden_sizes: new List<Tuple<int, uint>>());
}
}
public TaskCommon with(string id = null, string session = null, DateTime? create_time = null,
TaskType? task_type = null, string name = null, TaskExitCondition? exit_condition = null,
double? exit_condition_parameter = null, bool? rfq_only = null, double? rfq_quote_for_seconds = null, TaskEdgeType? edge_type = null,
string edge_surface = null,
double? bid_edge_param = null, double? bid_size_param = null,
double? ask_edge_param = null, double? ask_size_param = null,
TaskSide? side = null, DateTime? last_modification_time = null,
bool? auto_hedge = null,
List<Tuple<int, double>> overridden_edges = null,
List<Tuple<int, uint>> overridden_sizes = null) {
return new TaskCommon(id ?? this.id,
session ?? this.session,
create_time ?? this.create_time,
task_type ?? this.task_type,
name ?? this.name,
exit_condition ?? this.exit_condition,
exit_condition_parameter ?? this.exit_condition_parameter,
rfq_only ?? this.rfq_only,
rfq_quote_for_seconds ?? this.rfq_quote_for_seconds,
edge_type ?? this.edge_type,
edge_surface ?? this.edge_surface,
bid_edge_param ?? this.bid_edge_param,
ask_edge_param ?? this.ask_edge_param,
bid_size_param ?? this.bid_size_param,
ask_size_param ?? this.ask_size_param,
side ?? this.side,
last_modification_time ?? this.last_modification_time,
auto_hedge ?? this.auto_hedge,
overridden_edges ?? this.overridden_edges,
overridden_sizes ?? this.overridden_sizes);
}
}
}
@@ -1,70 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace mbts.tasks
{
/// Task persisted state combined with
/// the live running state
public class TaskLiveData : IEquatable<TaskLiveData>
{
public readonly ElectronicTradingTask task;
public readonly TaskSwitchState switch_state;
public readonly TaskHealthState task_state;
public readonly double net_accumulation, abs_accumulation;
public TaskLiveData(ElectronicTradingTask task, TaskSwitchState switch_state, TaskHealthState health_state,
double net_accumulation, double abs_accumulation)
{
this.task = task;
this.switch_state = switch_state;
this.task_state = health_state;
this.net_accumulation = net_accumulation;
this.abs_accumulation = abs_accumulation;
}
public string task_id { get { return task.common.id; } }
public TaskType task_type { get { return task.common.task_type; } }
public string name { get { return task.common.name; } }
public double completion_ratio { get { return abs_accumulation / task.common.exit_condition_parameter; } }
public bool is_filled { get { return completion_ratio >= 1.0; } }
public DateTime modification_time { get { return task.common.last_modification_time; } }
public TaskLiveData with(ElectronicTradingTask task = null, TaskSwitchState? switch_state = null, TaskHealthState? task_state = null,
double? net_accumulation = null, double? abs_accumulation = null)
{
return new TaskLiveData(task ?? this.task,
switch_state ?? this.switch_state,
task_state ?? this.task_state,
net_accumulation ?? this.net_accumulation,
abs_accumulation ?? this.abs_accumulation);
}
public int GetHashCode(TaskLiveData obj) { return obj.task_id.GetHashCode(); }
public bool Equals(TaskLiveData other)
{
return ReferenceEquals(task, other.task) &&
switch_state == other.switch_state &&
task_state == other.task_state &&
completion_ratio == other.completion_ratio;
}
public override string ToString()
{
return task.ToString();
}
public string get_summary_text()
{
string sign = task.common.side == TaskSide.Buy ? "+" : (task.common.side == TaskSide.Sell ? "-" : "+/-");
return String.Format("{0}{1} ({2}/{3})", sign, task.common.name, abs_accumulation, task.common.exit_condition_parameter);
}
}
}
@@ -1,50 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace mbts.tasks {
public class TaskSecurityEyeData {
public TaskSecurityEyeData() {
}
public bool is_output_present {
get {
return false;
}
}
public bool is_on {
get {
return false;
}
}
/// If the security is on, returns the edge as sent by the eye
/// otherwise returns the input edge
public double edge {
get {
return Double.NaN;
}
}
/// If the security is on, returns the size as sent by the eye
/// otherwise returns the input size
public uint size {
get {
return 0;
}
}
public double eye_published_price {
get {
// if (is_on && is_output_present)
// return input.secside_key.side == bts.o2.msgs.Side.type.BUY ? output.price - output.edge : output.price + output.edge;
// return Double.NaN;
return Double.NaN;
}
}
}
}
@@ -48,53 +48,3 @@ namespace mbts.engine {
}
}
}
namespace BCG {
public class TaskingConsolidatedData {
public TaskingConsolidatedData(IEnumerable<TaskLiveData> input_tasks,
object input_securities,
object eye_output,
object quoter_output) {
}
public readonly static TaskingConsolidatedData empty = new TaskingConsolidatedData(Enumerable.Empty<TaskLiveData>(),
null, null, null);
// public TaskingConsolidatedData with(IEnumerable<TaskLiveData> input_tasks = null,
// IEnumerable<TaskSecurityData> input_securities = null,
// IEnumerable<EyeSecurityState> eye_output = null,
// IEnumerable<QuoterSecurityState> quoter_output = null) {
// return new TaskingConsolidatedData(input_tasks ?? this._input_tasks, input_securities ?? this._input_securities,
// eye_output ?? _eye_output, quoter_output ?? _quoter_output);
// }
public IEnumerable<TaskLiveData> get_tasks(TaskType task_type) { return new TaskLiveData[] { }; }
public TaskLiveData get_task_by_name(TaskType task_type, string name) {
IEnumerable<TaskLiveData> live_tasks = get_tasks(task_type);
return live_tasks.FirstOrDefault(lt => lt.task.common.name == name);
}
public IEnumerable<TaskLiveData> get_security_owning_tasks(IEnumerable<SecuritySideKey> secside_keys, TaskType t_type) {
HashSet<TaskLiveData> rv = new HashSet<TaskLiveData>();
return rv;
}
public HashSet<uint> get_set_securities(TaskType task_type, bool is_on_only = false) {
return new HashSet<uint>();
}
public TaskSecurityEyeData get_eye_data(uint key, Side side) { return get_eye_data(new SecuritySideKey(key, side)); }
public TaskSecurityEyeData get_eye_data(SecuritySideKey key) {
return new TaskSecurityEyeData();
}
public TaskSecurityQuoterData get_quoter_data(uint key, Side side) { return get_quoter_data(new SecuritySideKey(key, side)); }
public TaskSecurityQuoterData get_quoter_data(SecuritySideKey key) {
return new TaskSecurityQuoterData();
}
public TaskLiveData get_security_task(SecuritySideKey key, TaskType task_type) {
return null;
}
}
}
@@ -123,6 +123,15 @@ namespace BCG {
#endregion
#region Orders
[System.ComponentModel.Category("Orders / Algo")]
[System.ComponentModel.DisplayName("Default Account")]
public string Account { get; set; }
[System.ComponentModel.Category("Orders / Algo")]
[System.ComponentModel.DisplayName("Default Qty")]
public Nullable<double> DefaultQty { get; set; }
#endregion
public NMSheetSettingLayout() {
show_settings_header = false;
show_exp_navigator = false;
@@ -18,6 +18,7 @@ using mbts.spark.filters;
using System.Collections;
using System.Reactive.Linq;
using System.Threading;
using bts.api.orderman;
namespace BCG {
public partial class NMSheetControl : UserControl {
@@ -555,6 +556,17 @@ namespace BCG {
}
private void _launch_order_entry_window(NMSheetTheoGrid.GridCell cell,
OrderEntryWindow window_type) {
Func<string, bts.AccountTuple> get_account = (string default_acc) => {
string account = _settings.setting_layout.Account;
if (String.IsNullOrEmpty(account)) {
account = default_acc;
}
Nullable<uint> id = _get_account_id(account);
if (!id.HasValue) {
id = 0;
}
return new bts.AccountTuple(id.Value, account);
};
uint key;
var found = _sheet_data.get_security_key(cell.expiration,
cell.strike, cell.call_selected, out key);
@@ -566,7 +578,20 @@ namespace BCG {
if (sc_data.sec_md_map.TryGetValue(key, out var smd)) {
switch (window_type) {
case OrderEntryWindow.Ticket:
_threaded_bb.post(SparkTags.ShowOrderTicketFromSecurityTag, smd);
bool is_bid = NMSheetSettingColumnOrganization.get_column_info(cell.col).is_bid;
bts.AccountTuple acc_tup = get_account("SMALL");
Nullable<double> qty = _settings.setting_layout.DefaultQty;
OrderDefinition od = new OrderDefinition() {
SecurityKey = smd.id,
TimeInForce = TimeInForce.Gtc,
Account = acc_tup.name,
AccountId = acc_tup.id
};
BBOPacket bbo = _sheet_data.get_bbo(smd.id);
Tuple<double, UInt32> pr_sz = BBOPacket.get_md(bbo, is_bid);
UInt32 effective_qty = qty.HasValue ? Convert.ToUInt32(Math.Abs(qty.Value)) : pr_sz.Item2;
_threaded_bb.post(SparkTags.ShowOrderTicketTag,
(new OrderDefinitionImmutable(od), pr_sz.Item1, effective_qty));
break;
case OrderEntryWindow.Ladder:
_threaded_bb.post(SparkTags.ShowLadderTag, smd);
@@ -87,21 +87,21 @@ namespace BCG {
}
private void _refresh_task_data(uint seckey) {
string eye_task_text = String.Empty, quoter_task_text = String.Empty;
bool dummy, is_bid, is_ask;
NMSheetSettingColumnOrganization.parse_column(_last_mousemove_cell.col, out dummy, out dummy, out is_bid, out is_ask);
if (is_bid ^ is_ask) {
TaskingConsolidatedData task_data = _sheet_data.get_task_data();
mbts.tasks.TaskLiveData eye_task_ld = task_data != null ? task_data.get_security_task(new mbts.engine.SecuritySideKey(seckey, is_bid ? Side.Buy : Side.Sell), mbts.tasks.TaskType.Eye) : null;
if (eye_task_ld != null)
eye_task_text = String.Format("Eye '{0}' {1} {2}", eye_task_ld.name, eye_task_ld.switch_state.ToString().ToUpper(),
eye_task_ld.abs_accumulation.ToString("0") + "/" + eye_task_ld.task.common.exit_condition_parameter.ToString("0"));
mbts.tasks.TaskLiveData quoter_task_ld = task_data != null ? task_data.get_security_task(new mbts.engine.SecuritySideKey(seckey, is_bid ? Side.Buy : Side.Sell), mbts.tasks.TaskType.Quoter) : null;
if (quoter_task_ld != null)
quoter_task_text += String.Format("Quoter '{0}' {1} {2}", quoter_task_ld.name, quoter_task_ld.switch_state.ToString().ToUpper(),
quoter_task_ld.abs_accumulation.ToString("0") + "/" + quoter_task_ld.task.common.exit_condition_parameter.ToString("0"));
}
_set_text_visibility(_statusbar_toolstripstatus_task, true, String.Format("{0}{1}{2}", eye_task_text, String.IsNullOrEmpty(eye_task_text) ? String.Empty : " ", quoter_task_text));
// string eye_task_text = String.Empty, quoter_task_text = String.Empty;
// bool dummy, is_bid, is_ask;
// NMSheetSettingColumnOrganization.parse_column(_last_mousemove_cell.col, out dummy, out dummy, out is_bid, out is_ask);
// if (is_bid ^ is_ask) {
// TaskingConsolidatedData task_data = _sheet_data.get_task_data();
// mbts.tasks.TaskLiveData eye_task_ld = task_data != null ? task_data.get_security_task(new mbts.engine.SecuritySideKey(seckey, is_bid ? Side.Buy : Side.Sell), mbts.tasks.TaskType.Eye) : null;
// if (eye_task_ld != null)
// eye_task_text = String.Format("Eye '{0}' {1} {2}", eye_task_ld.name, eye_task_ld.switch_state.ToString().ToUpper(),
// eye_task_ld.abs_accumulation.ToString("0") + "/" + eye_task_ld.task.common.exit_condition_parameter.ToString("0"));
// mbts.tasks.TaskLiveData quoter_task_ld = task_data != null ? task_data.get_security_task(new mbts.engine.SecuritySideKey(seckey, is_bid ? Side.Buy : Side.Sell), mbts.tasks.TaskType.Quoter) : null;
// if (quoter_task_ld != null)
// quoter_task_text += String.Format("Quoter '{0}' {1} {2}", quoter_task_ld.name, quoter_task_ld.switch_state.ToString().ToUpper(),
// quoter_task_ld.abs_accumulation.ToString("0") + "/" + quoter_task_ld.task.common.exit_condition_parameter.ToString("0"));
// }
// _set_text_visibility(_statusbar_toolstripstatus_task, true, String.Format("{0}{1}{2}", eye_task_text, String.IsNullOrEmpty(eye_task_text) ? String.Empty : " ", quoter_task_text));
}
private static void _set_text_visibility(System.Windows.Forms.ToolStripStatusLabel l, bool new_visibility, string new_text) {
@@ -1,99 +0,0 @@
using mbts;
using mbts.tasks;
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace BCG {
partial class NMSheetControl {
//private bool _task_quoter_enabled = true;
private void _init_task_quoter_ui() {
// _task_quoter_enabled = true;
// if (_task_quoter_enabled)
// _disable_task_quoter_submenus();
// else
// _toolstripmenuitem_task_quoter.Enabled = false;
// _toolstripmenuitem_settings_show_task_quoter_data.Click += (s, e) => _get_toolstripmenuitem_display_state_and_publish(_toolstripmenuitem_settings_show_task_quoter_data,
// NMSheetSettingColumnOrganization.get_cols_for_type(NMSheetColumnType.Quoter).ToArray());
}
private void _disable_task_quoter_submenus() {
// _toolstripmenuitem_task_quoter.Enabled = _toolstripmenuitem_task_quoter_add_buys_to_task.Enabled =
// _toolstripmenuitem_task_quoter_add_sells_to_task.Enabled = _toolstripmenuitem_task_quoter_add_buys_and_sells_to_task.Enabled = false;
// _toolstripmenuitem_task_quoter_add_buys_to_task.DropDownItems.Clear();
// _toolstripmenuitem_task_quoter_add_sells_to_task.DropDownItems.Clear();
// _toolstripmenuitem_task_quoter_add_buys_and_sells_to_task.DropDownItems.Clear();
// List<ToolStripItem> create_menu_items = new List<ToolStripItem>();
// foreach (ToolStripItem ti in _toolstripmenuitem_task_quoter.DropDownItems)
// if (_create_menu_tag.Equals(ti.Tag))
// create_menu_items.Add(ti);
// create_menu_items.ForEach(ti => _toolstripmenuitem_task_quoter.DropDownItems.Remove(ti));
}
private void _adapt_contextmenu_for_tasks_quoter() {
// if (_task_quoter_enabled) {
// _disable_task_quoter_submenus();
// if (_task_selection.is_active) {
// _toolstripmenuitem_task_quoter.Enabled = true;
// ///Create
// IEnumerable<TaskCommon> templates = _threaded_bb.sec_thread_retrieve_from_cache(TaskingTags.TemplatesTag) as IEnumerable<TaskCommon>;
// templates = templates == null || templates.Count() == 0 ? new TaskCommon[] { TaskCommon.Default.with(name: "New Task") } : templates;
// double min_strike = _task_selection.strikes.Min(), max_strike = _task_selection.strikes.Max();
// string name = TaskType.Quoter.ToString() + " " +
// _task_selection.exp.get_display_text() + " " +
// (min_strike == max_strike ? min_strike.ToString("0.00") : String.Format("{0} - {1}", min_strike.ToString("0.00"), max_strike.ToString("0.00")));
// int add_task_index = 0;
// foreach (TaskCommon t in templates) {
// ToolStripMenuItem add_task_item = new ToolStripMenuItem(t.name, null, (s, e) => {
// mbts.tasks.TaskCommon common_task = t.with(task_type: TaskType.Quoter, name: name, side: TaskSide.None, id: Guid.NewGuid().ToString());
// ExplicitTask explicit_task = ExplicitTask.Default.with(securities: _task_selection.keys, security_descriptions: _task_selection.names);
// _threaded_bb.sec_thread_write(TaskingTags.ShowCreateTask, new ElectronicTradingTask(common_task, explicit_task));
// });
// add_task_item.Tag = _create_menu_tag;
// add_task_item.Enabled = true;
// _toolstripmenuitem_task_quoter.DropDownItems.Insert(add_task_index++, add_task_item);
// }
// //Add Buys to
// TaskingConsolidatedData task_data = _sheet_data.get_task_data();
// _toolstripmenuitem_task_quoter_add_buys_to_task.Enabled = true;
// IEnumerable<TaskLiveData> tasks = task_data.get_tasks(TaskType.Quoter).OrderBy(t => t.name);
// foreach (TaskLiveData t in tasks) {
// ElectronicTradingTask mod_task = _get_mod_task(t.task, _task_selection);
// ToolStripMenuItem add_item = new ToolStripMenuItem(t.get_summary_text(), null, (s, e) => _threaded_bb.sec_thread_write(TaskingTags.ShowEditTask, mod_task));
// add_item.Enabled = t.task.common.side != TaskSide.Sell;
// _toolstripmenuitem_task_quoter_add_buys_to_task.DropDownItems.Add(add_item);
// }
// /// Add Sells to
// _toolstripmenuitem_task_quoter_add_sells_to_task.Enabled = true;
// foreach (TaskLiveData t in tasks) {
// ElectronicTradingTask mod_task = _get_mod_task(t.task, _task_selection);
// ToolStripMenuItem add_item = new ToolStripMenuItem(t.get_summary_text(), null, (s, e) => _threaded_bb.sec_thread_write(TaskingTags.ShowEditTask, mod_task));
// add_item.Enabled = t.task.common.side != TaskSide.Buy;
// _toolstripmenuitem_task_quoter_add_sells_to_task.DropDownItems.Add(add_item);
// }
// /// Add Buys/Sells to
// _toolstripmenuitem_task_quoter_add_buys_and_sells_to_task.Enabled = true;
// foreach (TaskLiveData t in tasks) {
// ElectronicTradingTask mod_task = _get_mod_task(t.task, _task_selection);
// ToolStripMenuItem add_item = new ToolStripMenuItem(t.get_summary_text(), null, (s, e) => _threaded_bb.sec_thread_write(TaskingTags.ShowEditTask, mod_task));
// add_item.Enabled = t.task.common.side == (TaskSide.Buy | TaskSide.Sell);
// _toolstripmenuitem_task_quoter_add_buys_and_sells_to_task.DropDownItems.Add(add_item);
// }
// }
// }
}
// private ElectronicTradingTask _get_task_quoter_mod_task(ElectronicTradingTask task) {
// List<uint> secs = new List<uint>(task.explicit_task.securities);
// List<string> secs_desc = new List<string>(task.explicit_task.security_descriptions);
// secs.AddRange(_task_selection.keys);
// secs_desc.AddRange(_task_selection.names);
// ElectronicTradingTask mod_task = task.with(explicit_task: task.explicit_task.with(securities: secs, security_descriptions: secs_desc));
// return mod_task;
// }
}
}
@@ -83,26 +83,25 @@ namespace BCG {
}
private bool _get_ee_switch_override(NMSheetSettings settings, MyAlertHelperData helper_data, int exp_index, int strike_index, ref Color out_color) {
if (helper_data.is_ee_set_edge_or_size || helper_data.is_ee_price) {
NMSheetRowAuxiliaryData aux_data = _formatted_theos.get_aux_data(exp_index, strike_index);
if (aux_data != null) {
NMSheetCallPutBidAskWrapper<NMSheetTaskEyeData> eye_data = aux_data.task_ee_data;
if (eye_data != null) {
NMSheetTaskEyeData secside_eye_data = eye_data.get_data(helper_data.is_call, helper_data.is_bid);
if (secside_eye_data != null && secside_eye_data.eye_data != null) {
if (helper_data.is_ee_price) {
if (secside_eye_data.is_eye_cross) {
out_color = _settings.setting_alerts.ee_fire_color.Value;
return true;
}
}
if (secside_eye_data.eye_data.is_on) {
out_color = _settings.setting_alerts.ee_on_color.Value;
return true;
}
}
}
}
if (!helper_data.is_theo)
return false;
NMSheetRowAuxiliaryData aux_data = _formatted_theos.get_aux_data(exp_index, strike_index);
if (aux_data == null)
return false;
NMSheetCallPutBidAskWrapper<NMSheetTaskEyeData> t_data = aux_data.task_ee_data;
if (t_data == null)
return false;
NMSheetTaskEyeData bid_sec_t_data =
t_data.get_data(helper_data.is_call ? bts.api.PutOrCall.Call : bts.api.PutOrCall.Put,
bts.api.Side.Buy);
NMSheetTaskEyeData ask_sec_t_data =
t_data.get_data(helper_data.is_call ? bts.api.PutOrCall.Call : bts.api.PutOrCall.Put,
bts.api.Side.Sell);
if ((bid_sec_t_data != null && bid_sec_t_data.is_on) ||
(ask_sec_t_data != null && ask_sec_t_data.is_on)) {
out_color = settings.setting_alerts.ee_on_color.HasValue ?
settings.setting_alerts.ee_on_color.Value : Color.DarkGreen;
return true;
}
return false;
}
@@ -11,6 +11,8 @@ using System.Reactive.Linq;
using System.Windows.Input;
namespace mbts.spark {
using RegionalTickFactors = user.settings.RegionalTickFactors;
class InlineOrderTicketProperties {
public readonly InlineUserProperty<double> price;
public readonly InlineUserProperty<double> size;
@@ -102,6 +104,7 @@ namespace mbts.spark {
public SecurityImmutable security => _security.Value;
public double price { get; set; }
public RegionalTickFactors price_tick => security.regional_ticks();
public CalculatorLogic<double> size_calculator { get; }
public double display_quantity_divisor {
get => _display_quantity_divisor;
@@ -225,10 +225,7 @@ namespace bts.spark {
var security = try_get_security(order.Def.SecurityKey);
var change_descs = new List<string>(1);
TickDisplaySettingsImmutable? price_display =
security.HasValue && security.Value.HasContractSpec ?
security.Value.ContractSpec.tick_factors().to_api_tick_display_settingsi() : null;
var price_display = TickUtils.get_tick(security, price).to_api_tick_display_settingsi();
var price_qty_change_desc = OrderUtils.update_description(
order, price, size, price_display);
@@ -74,7 +74,7 @@
<usp:PriceEntryControl
Grid.ColumnSpan="2"
usp:OrderModificationControl.IsDirty="{Binding price_dirty, FallbackValue={x:Null}}"
ContractSpec="{Binding security.ContractSpec}"
RegionalTick="{Binding price_tick}"
Focusable="false"
TickDefaultValue="{Binding current_price, Converter={StaticResource TickDefaultPriceConverter}, FallbackValue={u:Double 0}}"
Value="{Binding price}"
@@ -29,7 +29,7 @@ namespace mbts.spark {
get {
var m = new OrderMetadata { KeyBinding = string.Empty, NoProps = false };
if (_studio_meta.HasValue && _studio_meta.Value.badge_color.HasValue)
m.Color = _studio_meta.Value.badge_color.Value.rgb_color();
m.Color = _studio_meta.Value.badge_color.Value.to_uint();
return m;
}
}
+5 -8
View File
@@ -254,17 +254,14 @@ namespace mbts.spark {
$"{(order.HasDef ? order.Def.Side.ToString() : "(unknown-side)")} {(order.HasState ? ($@"{spec.format(order.State.Price)} @ {order.State.Quantity}") : "(unknown-price) @ (unknown-quantity)")}";
public static string short_description(
SecurityImmutable security, Side side, double price, double quantity) =>
new StringBuilderEx(
SecurityImmutable security, Side side, double price, double quantity) {
var price_display = TickUtils.get_tick(security, price).to_api_tick_display_settingsi();
return new StringBuilderEx(
security.ToString(), " ",
side.ToString(), " ",
price_quantity_description(price, quantity, security.spec_or_default())
price_quantity_description(price, quantity, price_display)
).ToString();
public static string price_quantity_description(
double price, double quantity, ContractSpecificationImmutable spec) =>
price_quantity_description(
price, quantity, spec.tick_factors().to_api_tick_display_settingsi());
}
public static string price_quantity_description(
double price,
@@ -136,7 +136,7 @@ namespace mbts.analytics {
IEnumerable<VolSurfaceExpiration> all_exps) {
var exps = all_exps.Where(vse => vse.symbol.is_null_or_empty()).ToArray();
var exp_header_cells = exps
.Select(vse => DateFormatter.Format(vse.expiration, DateFormat.DayMonthAbvDiff2000))
.Select(vse => SecurityFormatter.format_expiration(vse.expiration))
.ToArray();
return (exps, exp_header_cells);
}
@@ -145,7 +145,7 @@ namespace mbts.analytics {
IEnumerable<VolSurfaceExpiration> all_exps) {
var exps = all_exps.ToArray();
var exp_header_cells = exps.Select(vse => string.IsNullOrEmpty(vse.symbol) ?
DateFormatter.Format(vse.expiration, DateFormat.DayMonthAbvDiff2000) : vse.symbol)
SecurityFormatter.format_expiration(vse.expiration) : vse.symbol)
.ToArray();
return (exps, exp_header_cells);
}
@@ -57,8 +57,6 @@
<analytics:ComboFutureDataColumn x:Key="FutureSymDataColumn" HeaderTemplate="{StaticResource SymHeaderTemplate}" ElementStyle="{StaticResource FutureSymDataElementStyle}" MinWidth="60" x:Shared="False" />
<analytics:ComboOptionDataColumn x:Key="OptionExpDataColumn" HeaderTemplate="{StaticResource ExpHeaderTemplate}" ElementStyle="{StaticResource OptionExpDataElementStyle}" MinWidth="60" x:Shared="False" />
<analytics:ComboOptionDataColumn x:Key="OptionSymDataColumn" HeaderTemplate="{StaticResource SymHeaderTemplate}" ElementStyle="{StaticResource OptionSymDataElementStyle}" MinWidth="60" x:Shared="False" />
<MenuItem x:Key="LaunchConfigurationEditorMenuItem" x:Shared="False" Header="Report Configuration..." Command="{Binding DataContext.launch_configuration_editor, Source={x:Reference ComboWindow}}" />
<MenuItem x:Key="ExportToCSVMenuItem" Header="Export To CSV..." Command="{Binding export_to_csv_command}" CommandParameter="{Binding DataContext.show_call_put, Source={x:Reference ComboWindow}}" />
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
@@ -99,14 +97,7 @@
VerticalGridLinesBrush="LightGray"
CanUserResizeColumns="False"
CanUserReorderColumns="False"
IsReadOnly="True"
>
<DataGrid.ContextMenu>
<ContextMenu>
<StaticResourceExtension ResourceKey="LaunchConfigurationEditorMenuItem" />
</ContextMenu>
</DataGrid.ContextMenu>
</c:DataGridEx>
IsReadOnly="True" />
</AdornerDecorator>
<GridSplitter Grid.Row="2" Height="3" Background="Black" HorizontalAlignment="Stretch" />
@@ -144,12 +135,6 @@
<TextBlock Text="{Binding Item.strike, RelativeSource={RelativeSource AncestorType=DataGridRow}}" />
</DataTemplate>
</DataGrid.RowHeaderTemplate>
<DataGrid.ContextMenu>
<ContextMenu>
<StaticResourceExtension ResourceKey="LaunchConfigurationEditorMenuItem" />
<StaticResourceExtension ResourceKey="ExportToCSVMenuItem" />
</ContextMenu>
</DataGrid.ContextMenu>
</c:DataGridEx>
</AdornerDecorator>
@@ -121,7 +121,7 @@ namespace mbts.analytics {
timer.stop();
Log.Ui.info($"PNLReportCalculator n_pos: {output.position_data.Count()} " +
$"n_day_trades: {output.day_trades.Count()} time(msecs): {timer.lastIntervalTime}");
_log_before_posting(output.position_data);
//_log_before_posting(output.position_data);
_bus.post(SparkTags.ReportBlackboardTags.PNL.PNLData, output);
});
}
@@ -1,5 +1,7 @@
#nullable enable
namespace mbts.analytics {
using bts.api;
using System;
using System.Diagnostics.Contracts;
@@ -17,13 +19,9 @@ namespace mbts.analytics {
symbol = null;
}
private static string _format_exp(DateTime exp) {
return mbts.ui.utility.ExpirationFormatter.DateFormatter.format_day_month_year(exp);
}
SlideGreekUnitKey(DateTime exp_date) {
exp = exp_date;
_unique_name = _format_exp(exp_date);
_unique_name = SecurityFormatter.format_expiration(exp_date);
type = GroupType.Exp;
symbol = null;
}
@@ -31,7 +29,7 @@ namespace mbts.analytics {
SlideGreekUnitKey(DateTime exp_date, string symbol) {
exp = exp_date;
this.symbol = symbol;
_unique_name = $"{_format_exp(exp_date)}:{symbol}";
_unique_name = $"{SecurityFormatter.format_expiration(exp_date)}:{symbol}";
type = GroupType.SymExp;
}
@@ -115,21 +115,21 @@ namespace mbts.analytics {
}
private void _handle_nonvol_data(VolSurfaceNonVolData vs_nonvol_data) {
bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_nonvol_data report {0}",
_report.ReportName));
// bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_nonvol_data report {0}",
// _report.ReportName));
_vs_nonvol_data = vs_nonvol_data;
}
private void _handle_future_prices(
IReadOnlyDictionary<SecurityExpiration, FutureTheoStructure> future_prices_map) {
bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_future_prices report {0}",
_report.ReportName));
// bts.Log.Gen.Diag(String.Format("SlideReportCalculator._handle_future_prices report {0}",
// _report.ReportName));
_future_prices_map = future_prices_map.ToDictionary(kv => kv.Key, kv => kv.Value.theo);
}
private void _handle_trades(IEnumerable<ITradeLogRow> trades) {
bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_trades report {0}",
_report.ReportName));
// bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_trades report {0}",
// _report.ReportName));
_all_trades = trades.Where(t => t.is_active);
if (_report.CalcMode == Report.Types.ReportCalculationMode.PositionOrTheoChange) {
_compute_dirty = true;
+1 -2
View File
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net7.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<Authors>Blue Trading Systems</Authors>
<Company>Blue Trading Systems</Company>
@@ -34,7 +34,6 @@
<PackageReference Include="System.Reactive.Interfaces" Version="5.0.0" />
<PackageReference Include="System.Reactive.Linq" Version="5.0.0" />
<PackageReference Include="System.Reactive.PlatformServices" Version="5.0.0" />
<PackageReference Include="System.Runtime.Experimental" Version="6.0.2" />
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<ProjectReference Include="../spark_api/spark_api.csproj" />
<ProjectReference Include="../spark_core/spark_core.csproj" />
@@ -71,7 +71,8 @@ namespace BCG {
foreach (string sym in temp.Keys) {
SortedList<DateTime, string> temp2 = temp[sym];
foreach (KeyValuePair<DateTime, string> kvp in temp2) {
string datecode = bts.api.DateFormatter.Format(kvp.Key, bts.api.DateFormat.MonthCodeLastDigitYear);
string datecode = bts.api.SecurityFormatter.format_expiration(
kvp.Key, date_format: bts.api.DateFormat.MonthCodeLastDigitYear);
string explegs = (temp.Keys.Count > 1) ? string.Concat(sym, datecode, "_", kvp.Value) :
string.Concat(datecode, "_", kvp.Value);
@@ -61,7 +61,7 @@ namespace BCG {
string rv = String.Empty;
foreach (SingleSpreadLeg l in legs)
rv += (rv == String.Empty ? "" : "/") + l.symbol + //BCG.Utilities.Dates.DateCode.getMonthSymbol(l.exp) + (l.exp.Year - 2000);
bts.api.DateFormatter.Format(l.exp, bts.api.DateFormat.DayMonthAbvDiff2000);
SecurityFormatter.format_expiration(l.exp);
return rv;
}
+2 -2
View File
@@ -35,7 +35,7 @@ namespace bts.core {
// TODO: for debugging purposes, remove it later
if (tag != mbts.spark.SparkTags.SparkTimer) {
var tid = System.Threading.Thread.CurrentThread.ManagedThreadId;
bts.Log.Ui.diag($"SimpleBus.post tag:{tag} tid:{tid}");
//bts.Log.Ui.diag($"SimpleBus.post tag:{tag} tid:{tid}");
return;
}
} catch (Exception e) {
@@ -45,7 +45,7 @@ namespace bts.core {
public IObservable<T> subscribe<T>(ITag<T> tag) {
var tid = System.Threading.Thread.CurrentThread.ManagedThreadId;
bts.Log.Ui.info($"SimpleBus.post tag:{tag} tid:{tid}");
//bts.Log.Ui.info($"SimpleBus.subscribe tag:{tag} tid:{tid}");
return subject<T>(tag);
}
}
+9 -1
View File
@@ -169,7 +169,7 @@ namespace mbts.spark {
public static ITag<int> CreateHeatmapTag { get; } = _mk_tag<int>();
// Publisher: VolSurfaceBlackboardManager
// User: VoLSurfaceModule
// User: VolSurfaceModule
public static ITag<IDictionary<int, string>> VolSurfaceListTag { get; } =
_mk_tag<IDictionary<int, string>>();
@@ -202,11 +202,17 @@ namespace mbts.spark {
public static ITag<VolSurfaceCalculationRequest> VolSurfaceCalculationRequestTag(int vs_id) =>
_mk_tag<VolSurfaceCalculationRequest, int>(vs_id);
public static ITag<VolSurfaceCalculationRequest> VolSurfaceAutoCalculationRequestTag(int vs_id) =>
_mk_tag<VolSurfaceCalculationRequest, int>(vs_id);
// Publisher : SingleVolSurfaceRequestCalculator
// Data : VolSurfaceCalculationResponse
public static ITag<VolSurfaceCalculationResponse> VolSurfaceCalculationResponseTag(int vs_id) =>
_mk_tag<VolSurfaceCalculationResponse, int>(vs_id);
public static ITag<VolSurfaceCalculationResponse> VolSurfaceAutoCalculationResponseTag(int vs_id) =>
_mk_tag<VolSurfaceCalculationResponse, int>(vs_id);
// When the UI intends to save the vol surface (data or input)
// Publisher: VolSurfaceDisplayModel
public static ITag<VolSurfaceInput> VolSurfaceCommitTag(int vs_id) =>
@@ -366,6 +372,8 @@ namespace mbts.spark {
public class Nothing { Nothing() { } }
public class TC2Tags {
public static ITag<NMSheetAllTaskingData> TaskData { get; } =
_mk_tag<NMSheetAllTaskingData>();
// Data request for a sheet
// Published by NMSheetDriverControlStrip
public static ITag<NMSheetDataRequest> NMSheetDataRequestTag(string id) =>
Loaded 100 of 215 files, more files were not shown because too many files have changed in this diff. Show more