Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
709334a1aa | ||
|
|
f9a6e0963c | ||
|
|
b2879837c6 | ||
|
|
0d03ddb009 | ||
|
|
a6dfa4ae80 | ||
|
|
e66ec82ba8 | ||
|
|
9ce5e971c6 | ||
|
|
3e7cc49ebb | ||
|
|
d07e68b6e2 | ||
|
|
619ece2313 | ||
|
|
1dda9566f3 | ||
|
|
a524ca02a5 | ||
|
|
3c97f2552b | ||
|
|
15b1d55ef1 | ||
|
|
4e42c9f01b | ||
|
|
76775f821a | ||
|
|
e7088f6b1c | ||
|
|
1fb42ade59 | ||
|
|
129650e9d4 | ||
|
|
170a44ac04 | ||
|
|
7e04f02327 | ||
|
|
abda2dbf97 | ||
|
|
ad1a45cf49 | ||
|
|
e9abdd0ff2 | ||
|
|
9254002318 | ||
|
|
596780b7f4 | ||
|
|
7ba061ac20 | ||
|
|
c01593d119 | ||
|
|
09e2a1764f | ||
|
|
a780668bce | ||
|
|
5b79aeaa14 | ||
|
|
049c006b5f | ||
|
|
6fdc344472 | ||
|
|
cb09b93553 | ||
|
|
21447d32e5 | ||
|
|
28b03e1cd2 | ||
|
|
a7acb89c15 | ||
|
|
35289710ba | ||
|
|
4677acfb39 | ||
|
|
ac05d0d69e | ||
|
|
25a9b6b433 | ||
|
|
b78713ad0d | ||
|
|
1f3d0e879c | ||
|
|
baad4dc68e | ||
|
|
ef7c0c7a30 | ||
|
|
3b3c4a2a35 | ||
|
|
ef9fc66a31 | ||
|
|
212d9c853b | ||
|
|
7815b18b6b | ||
|
|
05126074d4 | ||
|
|
3611d2c1f3 | ||
|
|
b5ad4b8104 | ||
|
|
43d7c0a2b5 | ||
|
|
12e361cec7 | ||
|
|
82c126362d | ||
|
|
fd2ba70031 | ||
|
|
ab410c339f | ||
|
|
9e3f16d8bc | ||
|
|
a3f194d708 | ||
|
|
bf87c46fcd | ||
|
|
222d4b266e | ||
|
|
d593eaf058 | ||
|
|
55d021ccb1 | ||
|
|
b02f814c65 | ||
|
|
8c42aa93a2 | ||
|
|
357bc5ad44 | ||
|
|
07fb9e8eb7 | ||
|
|
9f9fc4c8ab | ||
|
|
2aef052398 | ||
|
|
1c2027506a | ||
|
|
c3274b2008 | ||
|
|
99aef9e86e | ||
|
|
8e9233022e |
No files matched your search
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
Submodule externals updated: 4d96613ca8...4a3e40193e.
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
@@ -253,6 +253,7 @@ namespace mbts.ui {
|
||||
public static BTSColor foreground => UI.default_foreground;
|
||||
public static BTSColor anchor => Colors.Gold;
|
||||
public static BTSColor profit => Colors.Green;
|
||||
public static BTSColor net_zero => BTSCoreColors.gray;
|
||||
public static BTSColor loss => BTSCoreColors.venetian_red;
|
||||
public static BTSColor header_row_background => 0xffaaaaaa;
|
||||
// group background colors
|
||||
@@ -590,9 +591,9 @@ namespace mbts.ui {
|
||||
|
||||
// Disabled
|
||||
public static BTSColor disabled_border => UI.input_disabled_border;
|
||||
public static BTSColor disabled_background => UI.input_disabled_background;
|
||||
public static BTSColor disabled_foreground => normal_foreground;
|
||||
public static BTSColor disabled_text => normal_text;
|
||||
public static BTSColor disabled_background => Button.disabled_background;
|
||||
public static BTSColor disabled_foreground => Button.disabled_foreground;
|
||||
public static BTSColor disabled_text => Button.disabled_foreground;
|
||||
public static BTSColor disabled_glyph => normal_glyph;
|
||||
public static BTSColor disabled_button_border => BTSCoreColors.transparent;
|
||||
public static BTSColor disabled_button_background => BTSCoreColors.transparent;
|
||||
@@ -646,8 +647,7 @@ namespace mbts.ui {
|
||||
public static BTSColor pressed_editable_button_background => pressed_button_background;
|
||||
public static BTSColor pressed_editable_button_border => pressed_button_border;
|
||||
|
||||
public static BTSColor disabled_editable_background =>
|
||||
editable_background.blend(disabled_background);
|
||||
public static BTSColor disabled_editable_background => Core.transparent;
|
||||
|
||||
public static BTSColor disabled_editable_border =>
|
||||
editable_border.blend(disabled_border);
|
||||
@@ -1041,6 +1041,21 @@ namespace mbts.ui {
|
||||
public static BTSColor foreground => UI.default_text;
|
||||
public static BTSColor footer_foreground => foreground;
|
||||
}
|
||||
public static class ExecutionStrategy {
|
||||
public static BTSColor expander_background => Core.transparent;//Grid.dark_column_background;
|
||||
public static BTSColor expander_foreground => UI.default_text;
|
||||
public static BTSColor data_grid_row_header_background => Core.transparent;
|
||||
public static BTSColor data_grid_row_header_foreground => UI.default_text;
|
||||
public static BTSColor data_grid_background => Grid.default_row_background;
|
||||
public static BTSColor default_column_background => Grid.default_row_background;
|
||||
public static BTSColor alternate_column_background => Grid.alternate_row_background;// 0xff494957;
|
||||
public static BTSColor arrow_background => UI.default_text;
|
||||
public static BTSColor arrow_background_selected => UI.alternate_text;
|
||||
|
||||
}
|
||||
public static class ManualFills {
|
||||
public static BTSColor background => UI.common_background;
|
||||
}
|
||||
public static class AlgoStudio {
|
||||
public static BTSColor background => UI.default_background;
|
||||
public static BTSColor foreground => UI.default_foreground;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace bts.proto {
|
||||
readonly double _opacity;
|
||||
|
||||
public ColorOpacityProto(Color color = default, double opacity = 1.0)
|
||||
: this(color.rgb_color(), opacity) { }
|
||||
: this(color.to_uint(), opacity) { }
|
||||
|
||||
public ColorOpacityProto(uint color = 0u, double opacity = 1.0) {
|
||||
_color = color;
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace bts.proto {
|
||||
readonly bool _show;
|
||||
|
||||
public ColorShowProto(Color value, bool show = true)
|
||||
: this(value.rgb_color(), show) { }
|
||||
: this(value.to_uint(), show) { }
|
||||
|
||||
public ColorShowProto(uint value, bool show = true) {
|
||||
_value = value;
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
using bts.api;
|
||||
using bts.utils;
|
||||
|
||||
using mbts.utils;
|
||||
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
|
||||
namespace bts.proto {
|
||||
[ProtoContract]
|
||||
public struct ExpDate : IEquatable<ExpDate> {
|
||||
[ProtoMember(1)]
|
||||
readonly uint _month;
|
||||
[ProtoMember(2)]
|
||||
readonly uint _year;
|
||||
[ProtoMember(3)]
|
||||
readonly uint _day;
|
||||
|
||||
public ExpDate(SecurityImmutable security)
|
||||
: this(security.earliest_expiration()) { }
|
||||
|
||||
public ExpDate(DateTime date) {
|
||||
_month = (uint)date.Month;
|
||||
_year = (uint)date.Year;
|
||||
_day = (uint)date.Day;
|
||||
}
|
||||
|
||||
public uint month => _month;
|
||||
public uint year => _year;
|
||||
public uint day => _day;
|
||||
|
||||
public bool Equals(ExpDate other) =>
|
||||
other._month == _month && other._year == year && other._day == day;
|
||||
|
||||
public override bool Equals(object obj) => obj is ExpDate ed && Equals(ed);
|
||||
public static bool operator ==(ExpDate a, ExpDate b) => a.Equals(b);
|
||||
public static bool operator !=(ExpDate a, ExpDate b) => !a.Equals(b);
|
||||
|
||||
public override int GetHashCode() =>
|
||||
EqualityComparer.aggregate_hash((int)_month, (int)_day, (int)_year);
|
||||
|
||||
public override string ToString() =>
|
||||
DateFormatter.Format((int)_year, (int)_month, (int)_day, DateFormat.MonthCodeLastDigitYear);
|
||||
}
|
||||
|
||||
static class ExpDateExtensions {
|
||||
public static DateTime to_date_time(this ExpDate exp_date) =>
|
||||
new DateTime((int)exp_date.year, (int)exp_date.month, (int)exp_date.day);
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,42 @@
|
||||
using bts.utils;
|
||||
|
||||
using mbts.ui;
|
||||
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
using System.Windows.Media;
|
||||
|
||||
#nullable enable
|
||||
namespace bts.proto {
|
||||
using bts.utils;
|
||||
|
||||
using mbts.ui;
|
||||
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Windows.Media;
|
||||
|
||||
[ProtoContract]
|
||||
struct NullableColorProto : IEquatable<NullableColorProto> {
|
||||
readonly struct NullableColorProto : IEquatable<NullableColorProto> {
|
||||
[ProtoMember(1)]
|
||||
readonly uint? _value;
|
||||
|
||||
public NullableColorProto(Color? value) =>
|
||||
_value = value?.rgb_color();
|
||||
_value = value?.to_uint();
|
||||
|
||||
public NullableColorProto(uint value) =>
|
||||
_value = value;
|
||||
public static NullableColorProto none => new(null);
|
||||
|
||||
public Color? value => _value?.rgb_color();
|
||||
public Color? argb => _value?.argb_color();
|
||||
public Color? value => _value?.argb_color();
|
||||
|
||||
[MemberNotNullWhen(true, nameof(value))]
|
||||
public bool has_value => value.HasValue;
|
||||
|
||||
public bool Equals(NullableColorProto other) =>
|
||||
EqualityComparer.nullable_equals(_value, other._value);
|
||||
|
||||
public override bool Equals(object obj) =>
|
||||
public override bool Equals(object? obj) =>
|
||||
obj is NullableColorProto ncp && Equals(ncp);
|
||||
|
||||
public override int GetHashCode() =>
|
||||
_value.HasValue ? (int)_value.Value : 0;
|
||||
|
||||
public override string ToString() =>
|
||||
_value?.ToString() ?? string.Empty;
|
||||
|
||||
public static bool operator ==(NullableColorProto a, NullableColorProto b) => a.Equals(b);
|
||||
public static bool operator !=(NullableColorProto a, NullableColorProto b) => !a.Equals(b);
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
using bts.utils;
|
||||
|
||||
using mbts.utils;
|
||||
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
|
||||
namespace mbts.ui.settings {
|
||||
[ProtoContract]
|
||||
struct NullableFontWeightProto : IEquatable<NullableFontWeightProto> {
|
||||
[ProtoMember(1)]
|
||||
readonly ushort? _value;
|
||||
|
||||
public NullableFontWeightProto(FontWeight? value) =>
|
||||
_value = (ushort?)value?.ToOpenTypeWeight();
|
||||
|
||||
public NullableFontWeightProto(ushort value) =>
|
||||
_value = value;
|
||||
|
||||
public FontWeight? value {
|
||||
get {
|
||||
if (_value.HasValue)
|
||||
return FontWeight.FromOpenTypeWeight(_value.Value);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(NullableFontWeightProto other) =>
|
||||
EqualityComparer.nullable_equals(_value, other._value);
|
||||
|
||||
public override bool Equals(object obj) =>
|
||||
obj is NullableFontWeightProto ncp && Equals(ncp);
|
||||
|
||||
public override int GetHashCode() =>
|
||||
_value.HasValue ? _value.Value : 0;
|
||||
|
||||
public static bool operator ==(NullableFontWeightProto a, NullableFontWeightProto b) => a.Equals(b);
|
||||
public static bool operator !=(NullableFontWeightProto a, NullableFontWeightProto b) => !a.Equals(b);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#nullable enable
|
||||
namespace bts.proto {
|
||||
using bts.utils;
|
||||
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Windows;
|
||||
|
||||
[ProtoContract]
|
||||
readonly struct NullableFontWeightProto : IEquatable<NullableFontWeightProto> {
|
||||
[ProtoMember(1)]
|
||||
readonly int? _value;
|
||||
|
||||
public NullableFontWeightProto(FontWeight? value) =>
|
||||
_value = value?.ToOpenTypeWeight();
|
||||
|
||||
public NullableFontWeightProto(int value) =>
|
||||
_value = value;
|
||||
|
||||
public static NullableFontWeightProto none =>
|
||||
new(null);
|
||||
|
||||
public FontWeight? value =>
|
||||
_value.HasValue ? FontWeight.FromOpenTypeWeight(_value.Value) : null;
|
||||
|
||||
[MemberNotNullWhen(true, nameof(value))]
|
||||
public bool has_value => value.HasValue;
|
||||
|
||||
public bool Equals(NullableFontWeightProto other) =>
|
||||
EqualityComparer.nullable_equals(_value, other._value);
|
||||
|
||||
public override bool Equals(object? obj) =>
|
||||
obj is NullableFontWeightProto fw && Equals(fw);
|
||||
|
||||
public override int GetHashCode() =>
|
||||
_value ?? 0;
|
||||
|
||||
public override string ToString() =>
|
||||
_value?.ToString() ?? string.Empty;
|
||||
|
||||
public static bool operator ==(NullableFontWeightProto a, NullableFontWeightProto b) =>
|
||||
a.Equals(b);
|
||||
|
||||
public static bool operator !=(NullableFontWeightProto a, NullableFontWeightProto b) =>
|
||||
!a.Equals(b);
|
||||
}
|
||||
}
|
||||
@@ -76,6 +76,11 @@
|
||||
<Color x:Key="ComboBox.Pressed.Editable.BackgroundColor">#707070</Color>
|
||||
<Color x:Key="ComboBox.Pressed.Editable.Button.BackgroundColor">#FFC4E0FC</Color>
|
||||
|
||||
<Color x:Key="ComboBox.Disabled.Editable.BackgroundColor">#FFE5E5E5</Color>
|
||||
<Color x:Key="ComboBox.Disabled.Editable.BorderColor">#FFD9D9D9</Color>
|
||||
<Color x:Key="ComboBox.Disabled.Editable.Button.BackgroundColor">#FFE5E5E5</Color>
|
||||
<Color x:Key="ComboBox.Disabled.Editable.Button.BorderColor">#FFD9D9D9</Color>
|
||||
|
||||
<SolidColorBrush x:Key="ComboBox.Static.Background" Color="{StaticResource ComboBox.Static.BackgroundColor}" />
|
||||
<SolidColorBrush x:Key="ComboBox.Static.Foreground" Color="{StaticResource ComboBox.Static.ForegroundColor}" />
|
||||
<SolidColorBrush x:Key="ComboBox.Static.Border" Color="{StaticResource ComboBox.Static.BorderColor}"/>
|
||||
@@ -98,7 +103,7 @@
|
||||
<SolidColorBrush x:Key="ComboBox.Disabled.Border" Color="{StaticResource ComboBoxDisabledBorderColor}"/>
|
||||
<SolidColorBrush x:Key="ComboBox.Disabled.Editable.Background" Color="{StaticResource ComboBox.Disabled.Editable.BackgroundColor}" />
|
||||
<SolidColorBrush x:Key="ComboBox.Disabled.Editable.Border" Color="{StaticResource ComboBox.Disabled.Editable.BorderColor}" />
|
||||
<SolidColorBrush x:Key="ComboBox.Disabled.Editable.Button.Background" Color="{StaticResource ComboBox.Disabled.Editable.BackgroundColor}" />
|
||||
<SolidColorBrush x:Key="ComboBox.Disabled.Editable.Button.Background" Color="{StaticResource ComboBox.Disabled.Editable.Button.BackgroundColor}" />
|
||||
<SolidColorBrush x:Key="ComboBox.Disabled.Editable.Button.Border" Color="{StaticResource ComboBox.Disabled.Editable.Button.BorderColor}" />
|
||||
<SolidColorBrush x:Key="ComboBox.Static.Glyph" Color="#FF606060"/>
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<Setter Property="Focusable" Value="False"/>
|
||||
<Setter Property="IsTabStop" Value="False"/>
|
||||
<Setter Property="OverridesDefaultStyle" Value="True"/>
|
||||
<Setter Property="Background" Value="{u:BTSColor ScrollBar.thumb_pressed}"/>
|
||||
<Setter Property="Background" Value="{u:BTSColor UI.ScrollBar.thumb_pressed}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Thumb">
|
||||
@@ -224,18 +224,18 @@
|
||||
<VisualState Name="Normal"/>
|
||||
<VisualState Name="MouseOver">
|
||||
<Storyboard>
|
||||
<ColorAnimation Storyboard.TargetProperty="Background.Color" BeginTime="0" Duration="0" To="{u:BTSColor ScrollBar.thumb_mouse_over}"/>
|
||||
<ColorAnimation Storyboard.TargetProperty="Background.Color" BeginTime="0" Duration="0" To="{u:BTSColor UI.ScrollBar.thumb_mouse_over}"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState Name="Pressed">
|
||||
<Storyboard>
|
||||
<ColorAnimation Storyboard.TargetProperty="Background.Color" BeginTime="0" Duration="0" To="{u:BTSColor ScrollBar.thumb_pressed}"/>
|
||||
<ColorAnimation Storyboard.TargetProperty="Background.Color" BeginTime="0" Duration="0" To="{u:BTSColor UI.ScrollBar.thumb_pressed}"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<Thumb.Background>
|
||||
<SolidColorBrush Color="{u:BTSColor ScrollBar.thumb_static}"/>
|
||||
<SolidColorBrush Color="{u:BTSColor UI.ScrollBar.thumb_static}"/>
|
||||
</Thumb.Background>
|
||||
</Thumb>
|
||||
</Track.Thumb>
|
||||
@@ -380,18 +380,18 @@
|
||||
<VisualState Name="Normal"/>
|
||||
<VisualState Name="MouseOver">
|
||||
<Storyboard>
|
||||
<ColorAnimation Storyboard.TargetProperty="Background.Color" BeginTime="0" Duration="0" To="{StaticResource u:BTSColor ScrollBar.thumb_mouse_over}"/>
|
||||
<ColorAnimation Storyboard.TargetProperty="Background.Color" BeginTime="0" Duration="0" To="{StaticResource u:BTSColor UI.ScrollBar.thumb_mouse_over}"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState Name="Pressed">
|
||||
<Storyboard>
|
||||
<ColorAnimation Storyboard.TargetProperty="Background.Color" BeginTime="0" Duration="0" To="{u:BTSColor ScrollBar.thumb_presseds}"/>
|
||||
<ColorAnimation Storyboard.TargetProperty="Background.Color" BeginTime="0" Duration="0" To="{u:BTSColor UI.ScrollBar.thumb_presseds}"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<Thumb.Background>
|
||||
<SolidColorBrush Color="{u:BTSColor ScrollBar.thumb_static}"/>
|
||||
<SolidColorBrush Color="{u:BTSColor UI.ScrollBar.thumb_static}"/>
|
||||
</Thumb.Background>
|
||||
</Thumb>
|
||||
</Track.Thumb>
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace mbts.ui.controls {
|
||||
color = brush.Color;
|
||||
opacity = brush.Opacity;
|
||||
}
|
||||
public ColorOpacityProto to_proto() => new ColorOpacityProto(color.rgb_color(), opacity);
|
||||
public ColorOpacityProto to_proto() => new ColorOpacityProto(color.to_uint(), opacity);
|
||||
}
|
||||
|
||||
class NamedColorPickerPopupVM : ColorPickerPopupVM {
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace mbts.ui.settings {
|
||||
public bool is_expanded => _is_expanded;
|
||||
public FontWeight? font_weight_override => _font_weight_override.value;
|
||||
public Color? font_color_override => _font_color_override.value;
|
||||
public Color? background_color_override => _background_color_override.argb;
|
||||
public Color? background_color_override => _background_color_override.value;
|
||||
public double width => _width;
|
||||
public HorizontalAlignment horizontal_alignment => _horizontal_alignment;
|
||||
public double horizontal_offset => _horizontal_offset;
|
||||
@@ -126,7 +126,7 @@ namespace mbts.ui.settings {
|
||||
width ?? this.width,
|
||||
horizontal_alignment ?? this.horizontal_alignment,
|
||||
horizontal_offset ?? this.horizontal_offset,
|
||||
(background_color_override ?? _background_color_override).argb);
|
||||
(background_color_override ?? _background_color_override).value);
|
||||
|
||||
public GridColumnSettings Clone() =>
|
||||
ProtobufSerializationHelper.clone(this);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
public static GridSettings Default =>
|
||||
new GridSettings(
|
||||
selection_highlight: Colors.MediumSlateBlue.with(0x63).argb_color(),
|
||||
selection_highlight: Colors.MediumSlateBlue.with(0x63).to_uint(),
|
||||
background: BTSColors.Grid.default_column_background,
|
||||
font_color: BTSColors.Grid.default_column_foreground);
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ namespace mbts.ui.settings {
|
||||
var a = sl.A.within_range((byte)30, (byte)200);
|
||||
if (sl.A != a) {
|
||||
sl.A = a;
|
||||
new_settings = settings.with(selection_highlight: sl.rgb_color());
|
||||
new_settings = settings.with(selection_highlight: sl.to_uint());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,9 +137,9 @@ namespace mbts.spark {
|
||||
foreach (IGrouping<TPredicateData, CellAnimation> g in animations)
|
||||
animation_map.AddOrUpdate(g.Key, p => animation_tuple(c: g), (p, t) => t.cell_animations.AddRange(g));
|
||||
}
|
||||
return _create_settings_obj(new GridSettings(font_family.name(), font_size, font_weight, font_color.color.rgb_color(), selection_highlight.color.rgb_color(), col_settings,
|
||||
return _create_settings_obj(new GridSettings(font_family.name(), font_size, font_weight, font_color.color.to_uint(), selection_highlight.color.to_uint(), col_settings,
|
||||
background: background_color.color.with(
|
||||
(byte)(background_color.opacity.within_range(0, 1) * 255.0)).rgb_color()),
|
||||
(byte)(background_color.opacity.within_range(0, 1) * 255.0)).to_uint()),
|
||||
animation_map.Select(kv => PredicateAnimations.create_data<TRowData, TPredicateData>(kv.Key, kv.Value.cell_animations, kv.Value.row_animations, kv.Value.sounds)));
|
||||
//
|
||||
(List<RowAnimation> row_animations, List<SoundNotification> sounds, List<CellAnimation> cell_animations) animation_tuple(IEnumerable<RowAnimation> r = null, IEnumerable<SoundNotification> s = null, IGrouping<TPredicateData, CellAnimation> c = null) =>
|
||||
|
||||
@@ -120,10 +120,10 @@ namespace mbts.spark {
|
||||
font_family.name(),
|
||||
font_size,
|
||||
font_weight,
|
||||
font_color.color.rgb_color(),
|
||||
selection_highlight.color.rgb_color(),
|
||||
font_color.color.to_uint(),
|
||||
selection_highlight.color.to_uint(),
|
||||
columns.Select(c => c.create()),
|
||||
background: background_color.color.argb_color());
|
||||
background: background_color.color.to_uint());
|
||||
|
||||
public void load_from(GridSettings value) {
|
||||
if (value == null)
|
||||
|
||||
@@ -258,13 +258,13 @@ namespace mbts.spark {
|
||||
settings.title_font_params = new() {
|
||||
typeface = new(title_font_family, title_font_weight.ToOpenTypeWeight()),
|
||||
font_size = title_font_size,
|
||||
font_color = title_font_color.argb_color(),
|
||||
font_color = title_font_color.to_uint(),
|
||||
};
|
||||
|
||||
settings.font_params = new() {
|
||||
typeface = new(font_family, font_weight.ToOpenTypeWeight()),
|
||||
font_size = font_size,
|
||||
font_color = font_color.argb_color(),
|
||||
font_color = font_color.to_uint(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
<TextBlock
|
||||
x:Name="PART_Context"
|
||||
FontWeight="Bold"
|
||||
Foreground="{u:BTSBrush UI.default_text}"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="4,0,0,0"
|
||||
Text="{Binding context}"
|
||||
|
||||
Loaded 100 of 193 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user