Compare commits
77
Commits
list
...
v1.1.test2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfce23a33d | ||
|
|
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 | ||
|
|
4c91538f22 | ||
|
|
320427c9c5 | ||
|
|
5e8543902e |
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));
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
_window_factories = new() {
|
||||
new MarketViewWindowFactory(
|
||||
this, bus, settings_hub, orders_model, position_model, sec_meta_store),
|
||||
new OptionsViewWindowFactory(this, bus),
|
||||
new OptionsViewWindowFactory(this, orders_model, bus),
|
||||
new TimeAndSalesWindowFactory(this, bus, consumer, settings_hub, orders_model.security_auxiliary_model),
|
||||
};
|
||||
|
||||
|
||||
@@ -79,10 +79,12 @@ namespace bts.shell.market_view {
|
||||
var ask_col_index = columns.FindIndex(x => x.id == MarketViewWindowFactory.col_id(Columns.Ask));
|
||||
if (bid_col_index > -1 && ask_col_index > -1) {
|
||||
if (!columns[bid_col_index].background_color_override.HasValue) {
|
||||
columns[bid_col_index] = columns[bid_col_index].with(background_color_override: new NullableColorProto(BTSColors.MarketData.bid.value));
|
||||
columns[bid_col_index] = columns[bid_col_index].with(
|
||||
background_color_override: new(BTSColors.MarketData.bid));
|
||||
}
|
||||
if (!columns[ask_col_index].background_color_override.HasValue) {
|
||||
columns[ask_col_index] = columns[ask_col_index].with(background_color_override: new NullableColorProto(BTSColors.MarketData.ask.value));
|
||||
columns[ask_col_index] = columns[ask_col_index].with(
|
||||
background_color_override: new(BTSColors.MarketData.ask));
|
||||
}
|
||||
}
|
||||
// and enable background color upgrade
|
||||
|
||||
@@ -70,11 +70,13 @@ namespace bts.shell {
|
||||
bool applied = false;
|
||||
if (bid_col_index > -1 && ask_col_index > -1) {
|
||||
if (!columns[bid_col_index].background_color_override.HasValue) {
|
||||
columns[bid_col_index] = columns[bid_col_index].with(background_color_override: new NullableColorProto(BTSColors.MarketData.bid.value));
|
||||
columns[bid_col_index] = columns[bid_col_index].with(
|
||||
background_color_override: new(BTSColors.MarketData.bid));
|
||||
applied = true;
|
||||
}
|
||||
if (!columns[ask_col_index].background_color_override.HasValue) {
|
||||
columns[ask_col_index] = columns[ask_col_index].with(background_color_override: new NullableColorProto(BTSColors.MarketData.ask.value));
|
||||
columns[ask_col_index] = columns[ask_col_index].with(
|
||||
background_color_override: new(BTSColors.MarketData.ask));
|
||||
applied = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,12 +10,14 @@ namespace mbts.spark {
|
||||
|
||||
class OptionsViewWindowFactory : ShellWindowFactory<OptionsViewSettings> {
|
||||
readonly IBus _bus;
|
||||
readonly NMSheetAllTaskingDataSource _tasking_datasource;
|
||||
|
||||
public OptionsViewWindowFactory(IShellModule module, IBus bus)
|
||||
public OptionsViewWindowFactory(IShellModule module, OrdersModel orders_model, IBus bus)
|
||||
: base(module, OptionsViewWindow.WINDOW_TYPE) {
|
||||
_bus = bus;
|
||||
_dispose = bus.subscribe(SparkTags.show_default_options_view).OnDispatcher().Subscribe(
|
||||
sc => _bus.post(SparkTags.ShowWindow, _create(OptionsViewSettings.Default(sc))));
|
||||
_tasking_datasource = new NMSheetAllTaskingDataSource(orders_model, bus);
|
||||
}
|
||||
|
||||
public override Task<IShellWindow> load(OptionsViewSettings state) =>
|
||||
|
||||
@@ -176,10 +176,11 @@
|
||||
</usp:DataGridParameterCellTemplateConverter.QuantityMeasureTemplate>
|
||||
</usp:DataGridParameterCellTemplateConverter>
|
||||
<Style x:Key="ExpanderToggleButton" TargetType="ToggleButton">
|
||||
<Setter Property="Foreground" Value="{u:BTSColor ExecutionStrategy.expander_foreground}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ToggleButton">
|
||||
<Grid Background="Transparent">
|
||||
<Grid Background="{u:BTSColor ExecutionStrategy.expander_background}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="12" />
|
||||
<ColumnDefinition/>
|
||||
@@ -190,7 +191,7 @@
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,5,0,0"
|
||||
SnapsToDevicePixels="False"
|
||||
Stroke="#77333333"
|
||||
Stroke="{u:BTSColor ExecutionStrategy.arrow_background}"
|
||||
StrokeThickness="2"
|
||||
VerticalAlignment="Top"
|
||||
/>
|
||||
@@ -199,6 +200,7 @@
|
||||
ContentSource="{TemplateBinding Content}"
|
||||
Margin="3,0,0,0"
|
||||
/>
|
||||
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
@@ -211,7 +213,7 @@
|
||||
<Setter Property="Stroke" TargetName="arrow" Value="Black"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Stroke" TargetName="arrow" Value="#FF707070"/>
|
||||
<Setter Property="Stroke" TargetName="arrow" Value="{u:BTSColor ExecutionStrategy.arrow_background_selected}"/>
|
||||
<Setter Property="Foreground" Value="Gray"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
@@ -278,7 +280,8 @@
|
||||
<ColumnDefinition/>
|
||||
</SelectiveScrollingGrid.ColumnDefinitions>
|
||||
<DataGridRowHeader
|
||||
Background="Transparent"
|
||||
Foreground="{u:BTSColor ExecutionStrategy.expander_foreground}"
|
||||
Background="{u:BTSColor ExecutionStrategy.data_grid_row_header_background}"
|
||||
Padding="{Binding section_count, Converter={StaticResource RowHeaderGroupIndentConverter}}"
|
||||
FontWeight="{Binding font_weight, FallbackValue={u:FontWeight Normal}}"
|
||||
SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical"
|
||||
@@ -317,9 +320,17 @@
|
||||
<Style x:Key="DataGridRowStyle" TargetType="DataGridRow">
|
||||
<Setter Property="BorderThickness" Value="1,0"/>
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
<Setter Property="Background" Value="{u:BTSColor ExecutionStrategy.alternate_column_background}"/>
|
||||
<Setter Property="Template" Value="{StaticResource DataGridRowTemplate}"/>
|
||||
<Setter Property="usp:ExecutionStrategyEditor.RowHasErrors" Value="{Binding has_errors}"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="ListBox.AlternationIndex" Value="1">
|
||||
<Setter Property="Background" Value="{u:BTSColor ExecutionStrategy.data_grid_background}"/>
|
||||
</Trigger>
|
||||
<!-- <Trigger Property="ListBox.AlternationIndex" Value="2">
|
||||
<Setter Property="Background" Value="LightBlue"/>
|
||||
<Setter Property="Foreground" Value="Navy"/>
|
||||
</Trigger> -->
|
||||
<DataTrigger Binding="{Binding read_only}" Value="True">
|
||||
<Setter Property="TextElement.Foreground" Value="{u:BTSColor UI.input_disabled_text_dark}"/>
|
||||
<Setter Property="ToolTip">
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace mbts.spark {
|
||||
main_vm.rows.AddRange(parsed_synths.Select(ps => {
|
||||
var sec = ps.result;
|
||||
var r = new SyntheticImportRowVM(orders_model.admin_model.user.id, used_names.Contains) {
|
||||
tick_factors = TickUtils.get_regional_ticks(sec.ContractSpec).low_tick,
|
||||
tick_factors = TickUtils.get_regional_ticks(sec.immutable()).low_tick,
|
||||
name = sec.Synthetic.Name,
|
||||
parsed_synth = ps
|
||||
};
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace mbts.spark {
|
||||
public SyntheticEditorVM(SpreaderModel model, SecurityImmutable synthetic, ExecutionStrategyImmutable strategy, IObservable<bool> security_has_working_orders)
|
||||
: this(synthetic, strategy, false) {
|
||||
ExceptionAssert.InvalidOperation.That(synthetic.Id != 0, "This constructor may only be used for already-existing synthetic securities (id must be non-zero).");
|
||||
_tick_factors = TickUtils.get_regional_ticks(synthetic.ContractSpec).low_tick;
|
||||
_tick_factors = TickUtils.get_regional_ticks(synthetic).low_tick;
|
||||
if (TickUtils.is_integer_tick(synthetic.ContractSpec)) {
|
||||
_use_fractional_ticks = false;
|
||||
_integer_tick_size = DoubleHelper.to_optional_int32(synthetic.ContractSpec.LowTick) ?? 0;
|
||||
@@ -112,7 +112,7 @@ namespace mbts.spark {
|
||||
_set_ticks_automatically = false;
|
||||
_set_quantities_automatically = false;
|
||||
_set_price_mults_automatically = false;
|
||||
_tick_factors = TickUtils.get_regional_ticks(_synthetic.ContractSpec).low_tick;
|
||||
_tick_factors = TickUtils.get_regional_ticks(_synthetic.immutable()).low_tick;
|
||||
} else {
|
||||
_deduce_name();
|
||||
_deduce_ticks();
|
||||
@@ -411,7 +411,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
void _deduce_ticks() {
|
||||
_tick_factors = TickUtils.deduce_ticks(leg_tuples.Select(l => l.leg.Security.ContractSpec));
|
||||
_tick_factors = TickUtils.deduce_ticks(leg_tuples.Select(l => l.leg.Security.immutable()));
|
||||
RaisePropertyChanged(nameof(tick_factors));
|
||||
}
|
||||
|
||||
|
||||
@@ -371,6 +371,7 @@
|
||||
<usp:AlgoEditorView
|
||||
DataContext="{Binding selected_definition}"
|
||||
Background="Transparent"
|
||||
Foreground="{u:BTSColor UI.default_text}"
|
||||
BorderBrush="{Binding algo_root, Converter={StaticResource OrderTypeBrushConverter}}"
|
||||
Padding="12,8" />
|
||||
</ScrollViewer>
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace Spark.Trading {
|
||||
meta.Value.Value.PriceDisplay : Security.Defaults.price_display_settingsi;
|
||||
if (security.HasValue) {
|
||||
rv = rv.with(
|
||||
tick_factors: security.spec_or_default().tick_factors().to_api_tick_factors());
|
||||
tick_factors: security.Value.tick_factors().to_api_tick_factors());
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -410,13 +410,13 @@ namespace mbts.spark {
|
||||
day_change = new DaySettings {
|
||||
// (neutral)
|
||||
font = _default_font,
|
||||
background_color = Colors.Transparent.rgb_color(),
|
||||
background_color = Colors.Transparent.to_uint(),
|
||||
// negative
|
||||
negative_font_color = Colors.White.rgb_color(),
|
||||
negative_background_color = Colors.Red.rgb_color(),
|
||||
negative_font_color = Colors.White.to_uint(),
|
||||
negative_background_color = Colors.Red.to_uint(),
|
||||
// positive
|
||||
positive_font_color = Colors.White.rgb_color(),
|
||||
positive_background_color = Colors.Green.rgb_color()
|
||||
positive_font_color = Colors.White.to_uint(),
|
||||
positive_background_color = Colors.Green.to_uint()
|
||||
},
|
||||
session_low = _default_item,
|
||||
session_high = _default_item,
|
||||
@@ -431,8 +431,8 @@ namespace mbts.spark {
|
||||
public static LadderPanelPricePointSettings tt_default {
|
||||
get {
|
||||
var rv = historic_default;
|
||||
rv.day_change.background_color = Color.FromRgb(113, 201, 69).rgb_color();
|
||||
rv.day_change.font.font_color = Colors.Black.rgb_color();
|
||||
rv.day_change.background_color = Color.FromRgb(113, 201, 69).to_uint();
|
||||
rv.day_change.font.font_color = Colors.Black.to_uint();
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@@ -484,7 +484,7 @@ namespace mbts.spark {
|
||||
static ItemSettings _default_item =>
|
||||
new ItemSettings {
|
||||
font = _default_font,
|
||||
background_color = Colors.Transparent.rgb_color()
|
||||
background_color = Colors.Transparent.to_uint()
|
||||
};
|
||||
|
||||
[ProtoContract]
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace mbts.spark {
|
||||
security_key = use_self_security ? null : selected_security_key,
|
||||
price_type = _selected_price_type,
|
||||
display = new LadderMarketBreakLine {
|
||||
color = color.rgb_color(),
|
||||
color = color.to_uint(),
|
||||
show = show,
|
||||
refresh_mode = refresh_mode
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace mbts.spark {
|
||||
class LadderOrderVM : DisposableViewModelBase {
|
||||
static readonly Color _colorbg = Colors.White;
|
||||
static readonly Color _darkbg = Color.FromRgb(0xbf, 0xbf, 0xbf);
|
||||
static readonly Brush _color_bg_brush = _colorbg.rgb_color().rgb_brush();
|
||||
static readonly Brush _color_bg_brush = _colorbg.to_uint().rgb_brush();
|
||||
|
||||
readonly LadderVM _owner;
|
||||
readonly double _real_price;
|
||||
@@ -228,7 +228,7 @@ namespace mbts.spark {
|
||||
if (_orders.TryGetValue(order.Key, out var opm)) {
|
||||
algo_studio_abbreviation = (opm.meta?.abbreviation).is_null_or_empty() ?
|
||||
_abbreviate_algo(opm.algo) : opm.meta?.abbreviation ?? string.Empty;
|
||||
border = opm.meta?.badge_color?.rgb_color().rgb_brush() ?? border;
|
||||
border = opm.meta?.badge_color?.to_uint().rgb_brush() ?? border;
|
||||
}
|
||||
algo_type = order.order_type().is_bts_algo_type() ?
|
||||
order.order_type() : CustomOrderDefinition.CustomOneofCase.None;
|
||||
@@ -241,7 +241,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public OrderBookVM? create_orderbook_vm() {
|
||||
var ticks = _owner.spec.full_ticks_from_zero(real_price);
|
||||
var ticks = _owner.spec.count_ticks(real_price);
|
||||
if (!ticks.HasValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -42,13 +42,13 @@ namespace mbts.spark {
|
||||
public LadderPanelPricePointSettings.ItemSettings create() =>
|
||||
new LadderPanelPricePointSettings.ItemSettings {
|
||||
font = new FontParamsProto {
|
||||
font_color = font_color.rgb_color(),
|
||||
font_color = font_color.to_uint(),
|
||||
font_size = font_size,
|
||||
typeface = new(
|
||||
font_family.name() ?? TextUtils.StandardFontFamilyName,
|
||||
font_weight.ToOpenTypeWeight())
|
||||
},
|
||||
background_color = background_color.rgb_color(),
|
||||
background_color = background_color.to_uint(),
|
||||
show_label = show_label
|
||||
};
|
||||
|
||||
@@ -111,11 +111,11 @@ namespace mbts.spark {
|
||||
show_label = base_settings.show_label,
|
||||
background_color = base_settings.background_color,
|
||||
// negative
|
||||
negative_font_color = negative_font_color.rgb_color(),
|
||||
negative_background_color = negative_background_color.rgb_color(),
|
||||
negative_font_color = negative_font_color.to_uint(),
|
||||
negative_background_color = negative_background_color.to_uint(),
|
||||
// positive
|
||||
positive_font_color = positive_font_color.rgb_color(),
|
||||
positive_background_color = positive_background_color.rgb_color()
|
||||
positive_font_color = positive_font_color.to_uint(),
|
||||
positive_background_color = positive_background_color.to_uint()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ namespace mbts.spark {
|
||||
void increment_ticks_per_row() {
|
||||
var tpr = ticks_per_row;
|
||||
for (uint i = 1; i < 100; i++) {
|
||||
var new_tpr = TickUtils.fit_ticks_per_row_to_dollars(security.ContractSpec, ticks_per_row + i);
|
||||
var new_tpr = TickUtils.fit_ticks_per_row_to_dollars(security, ticks_per_row + i);
|
||||
if (new_tpr != tpr) {
|
||||
ticks_per_row = new_tpr;
|
||||
break;
|
||||
@@ -201,7 +201,7 @@ namespace mbts.spark {
|
||||
void decrement_ticks_per_row() {
|
||||
var tpr = ticks_per_row;
|
||||
for (uint i = 1; i < tpr; i++) {
|
||||
var new_tpr = TickUtils.fit_ticks_per_row_to_dollars(security.ContractSpec, tpr - i);
|
||||
var new_tpr = TickUtils.fit_ticks_per_row_to_dollars(security, tpr - i);
|
||||
if (new_tpr != tpr) {
|
||||
ticks_per_row = new_tpr;
|
||||
break;
|
||||
@@ -239,7 +239,8 @@ namespace mbts.spark {
|
||||
// since settings profiles may be shared among ladders
|
||||
// of different securities/tick sizes, the ticks per row setting
|
||||
// may need to be rounded to a number that is a factor of $1.00
|
||||
public uint? rounded_ticks_per_row => TickUtils.fit_ticks_per_row_to_dollars(_security.ContractSpec, ticks_per_row);
|
||||
public uint? rounded_ticks_per_row =>
|
||||
TickUtils.fit_ticks_per_row_to_dollars(_security, ticks_per_row);
|
||||
|
||||
public MarketSizeDisplayVM size_display { get; } = new MarketSizeDisplayVM();
|
||||
public SimpleGridSettingsVM mini_ob { get; } = new SimpleGridSettingsVM(OrderBookGridSettingsManager.hard_column_flags);
|
||||
@@ -700,8 +701,8 @@ namespace mbts.spark {
|
||||
font_weight = font_weight.ToOpenTypeWeight(),
|
||||
width = width,
|
||||
show = show,
|
||||
foreground = foreground.rgb_color(),
|
||||
background = background.rgb_color()
|
||||
foreground = foreground.to_uint(),
|
||||
background = background.to_uint()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace mbts.spark {
|
||||
IReadOnlyDictionary<uint, OrderSecurity> _cache = DictionaryHelper.empty<uint, OrderSecurity>();
|
||||
ImmutableDictionary<AlgoKey, LadderFavoriteAlgoMetadata> _favorite_algo_metadata_map =
|
||||
ImmutableDictionary<AlgoKey, LadderFavoriteAlgoMetadata>.Empty;
|
||||
ContractSpecificationImmutable? _spec;
|
||||
RegionalTickFactors? _spec;
|
||||
|
||||
LadderVM(
|
||||
IBus bus,
|
||||
@@ -243,10 +243,9 @@ namespace mbts.spark {
|
||||
|
||||
var orders_source = settings.Select(s => s.ticks_per_row).DistinctUntilChanged()
|
||||
.SelectSeries(tpr => {
|
||||
var spec = TickUtils.multiply_tick_size(security.ContractSpec, tpr);
|
||||
var spec = TickUtils.multiply_tick_size(security.regional_ticks(), tpr);
|
||||
var price_comp = Comparer<double>.Create((a, b) =>
|
||||
Comparer<int?>.Default.Compare(
|
||||
spec.full_ticks_from_zero(a), spec.full_ticks_from_zero(b)));
|
||||
Comparer<long?>.Default.Compare(spec.count_ticks(a), spec.count_ticks(b)));
|
||||
return _order_price_source(model.orders, price_comp, p => TickUtils.normalize_price(spec, p));
|
||||
});
|
||||
_day_change.Changed += (o, n) => RaisePropertyChanged(
|
||||
@@ -394,9 +393,10 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public SecurityImmutable security => _model.security;
|
||||
public ContractSpecificationImmutable spec => _spec ?? (
|
||||
public RegionalTickFactors spec => _spec ?? (
|
||||
_spec = TickUtils.multiply_tick_size(
|
||||
security.ContractSpec, current_settings?.ticks_per_row ?? 1)).Value;
|
||||
security.regional_ticks(), current_settings?.ticks_per_row ?? 1))
|
||||
?? RegionalTickFactors.Default;
|
||||
|
||||
public double display_quantity_divisor { get; }
|
||||
public LadderSettings current_settings { get; private set; }
|
||||
@@ -826,7 +826,7 @@ namespace mbts.spark {
|
||||
if (!price.is_real()) {
|
||||
msg = "not a real number";
|
||||
} else if (settlement.is_real()) {
|
||||
var ticks_from_settle = security.ContractSpec.tickdiff(price, settlement);
|
||||
var ticks_from_settle = security.tickdiff(price, settlement);
|
||||
if (ticks_from_settle.HasValue) {
|
||||
var max_cross = (current_settings?.ladder_order_limits?.max_settlement_cross_ticks)
|
||||
.as_nullable();
|
||||
@@ -858,7 +858,7 @@ namespace mbts.spark {
|
||||
} else {
|
||||
ulong _ = 0;
|
||||
_model.md.get_bbo(ref _, out var bid, out var ask);
|
||||
var mid = TickUtils.mid_tick(security.ContractSpec, bid.price, ask.price);
|
||||
var mid = TickUtils.mid_tick(security.regional_ticks(), bid.price, ask.price);
|
||||
_day_change.set(mid - md.settlement_price);
|
||||
}
|
||||
_volume.set(volume);
|
||||
|
||||
@@ -32,6 +32,8 @@ using System.Windows.Media.Animation;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace mbts.spark {
|
||||
using RegionalTickFactors = user.settings.RegionalTickFactors;
|
||||
|
||||
partial class LadderGridHost : Control {
|
||||
static readonly int _initial_row_count;
|
||||
static readonly bool _show_scrollbar;
|
||||
@@ -83,7 +85,6 @@ namespace mbts.spark {
|
||||
bool _price_dirty = false, _piq_dirty = false;
|
||||
LadderPriceList _price_list = new() {
|
||||
length = _initial_row_count,
|
||||
spec = Security.Defaults.ContractSpecificationImmutable
|
||||
};
|
||||
LadderPriceList _pending_price_list = null;
|
||||
IComparer<double> _price_comparer;
|
||||
@@ -384,16 +385,16 @@ namespace mbts.spark {
|
||||
|
||||
Column[] _columns { get; set; } = Array.Empty<Column>();
|
||||
IEnumerable<Column> _visible_columns => _columns.Where(c => c.settings.show);
|
||||
ContractSpecificationImmutable? _spec_backing;
|
||||
ContractSpecificationImmutable _spec {
|
||||
RegionalTickFactors _spec_backing;
|
||||
RegionalTickFactors _spec {
|
||||
get {
|
||||
if (_spec_backing.HasValue) {
|
||||
return _spec_backing.Value;
|
||||
if (_spec_backing is not null) {
|
||||
return _spec_backing;
|
||||
} else if (_vm != null) {
|
||||
_spec_backing = TickUtils.multiply_tick_size(security.ContractSpec, _settings?.ticks_per_row ?? 1);
|
||||
return _spec_backing.Value;
|
||||
_spec_backing = TickUtils.multiply_tick_size(security.regional_ticks(), _settings?.ticks_per_row ?? 1);
|
||||
return _spec_backing;
|
||||
}
|
||||
return Security.Defaults.ContractSpecificationImmutable;
|
||||
return RegionalTickFactors.Default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,6 +448,15 @@ namespace mbts.spark {
|
||||
return _price_list.high_tick + tick_diff;
|
||||
}
|
||||
|
||||
public bool scroll_to_tick(long tick) {
|
||||
if (tick > int.MaxValue) {
|
||||
Log.Ui.error(
|
||||
$"Unable to scroll to tick {tick} because it exceeds int.MaxValue");
|
||||
return false;
|
||||
}
|
||||
return scroll_to_tick((int)tick);
|
||||
}
|
||||
|
||||
public bool scroll_to_tick(int tick) {
|
||||
if (_vm is null || _settings is null || _scroll_viewer is null) {
|
||||
return false;
|
||||
@@ -460,21 +470,23 @@ namespace mbts.spark {
|
||||
|
||||
// The scrollbar's vertical offset won't change. Find the 'top tick' that will put the
|
||||
// target `tick` in the center of the viewport.
|
||||
var top_tick = (int)_get_target_top_tick(tick);
|
||||
if (_settings.animate_recenter) {
|
||||
var anim = new Int32Animation {
|
||||
From = _price_list.high_tick,
|
||||
To = top_tick,
|
||||
Duration = TimeSpan.FromSeconds(0.15)
|
||||
};
|
||||
var sb = new Storyboard();
|
||||
sb.Children.Add(anim);
|
||||
Storyboard.SetTarget(anim, this);
|
||||
Storyboard.SetTargetProperty(anim, new PropertyPath(TopTickProperty));
|
||||
sb.Begin();
|
||||
} else {
|
||||
_set_scrollbar_range(high_tick: top_tick);
|
||||
_refresh_prices();
|
||||
checked {
|
||||
var top_tick = (int)_get_target_top_tick(tick);
|
||||
if (_settings.animate_recenter) {
|
||||
var anim = new Int32Animation {
|
||||
From = (int)_price_list.high_tick,
|
||||
To = top_tick,
|
||||
Duration = TimeSpan.FromSeconds(0.15)
|
||||
};
|
||||
var sb = new Storyboard();
|
||||
sb.Children.Add(anim);
|
||||
Storyboard.SetTarget(anim, this);
|
||||
Storyboard.SetTargetProperty(anim, new PropertyPath(TopTickProperty));
|
||||
sb.Begin();
|
||||
} else {
|
||||
_set_scrollbar_range(high_tick: top_tick);
|
||||
_refresh_prices();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -744,12 +756,12 @@ namespace mbts.spark {
|
||||
internal double price_for_point(Point point) =>
|
||||
_price_for_row(_row_for_point(point));
|
||||
|
||||
static uint? _size_from_row(int row, IList<double> price_list, NativePriceSize[] depth, ContractSpecificationImmutable spec) {
|
||||
static uint? _size_from_row(int row, IList<double> price_list, NativePriceSize[] depth, RegionalTickFactors spec) {
|
||||
if (price_list == null || depth == null) return null;
|
||||
else return row <= price_list.Count ? _size_from_price(price_list[row], depth, spec) : null;
|
||||
}
|
||||
|
||||
static uint? _size_from_price(double price, NativePriceSize[] depth, ContractSpecificationImmutable spec) {
|
||||
static uint? _size_from_price(double price, NativePriceSize[] depth, RegionalTickFactors spec) {
|
||||
if (!double.IsNaN(price) && depth.TryGetFirst(nps => spec.tick_equals(price, nps.price), out NativePriceSize result))
|
||||
return result.size;
|
||||
return null;
|
||||
@@ -1099,10 +1111,16 @@ namespace mbts.spark {
|
||||
Log.assert(_price_dirty);
|
||||
_price_list = new LadderPriceList {
|
||||
length = _initial_row_count,
|
||||
spec = security.ContractSpec
|
||||
security = security
|
||||
};
|
||||
var mid_tick = security.ContractSpec.tickdiff(_mkt_break_lines.origin, 0) ?? 0;
|
||||
_set_scrollbar_range(high_tick: mid_tick + (_price_list.Count << 1));
|
||||
var mid_tick = security.tickdiff(_mkt_break_lines.origin, 0) ?? 0;
|
||||
if (mid_tick > int.MaxValue) {
|
||||
Log.Ui.error(
|
||||
$"Unable to set scrollbar range about mid_tick {mid_tick}: " +
|
||||
$"tick count exceeds int.MaxValue");
|
||||
} else {
|
||||
_set_scrollbar_range(high_tick: (int)mid_tick + (_price_list.Count << 1));
|
||||
}
|
||||
_price_dirty = true;
|
||||
}
|
||||
if (_price_dirty) {
|
||||
@@ -1181,12 +1199,12 @@ namespace mbts.spark {
|
||||
_price_list, _vm.md.settlement_price,
|
||||
_settings.net_change == LadderSettings.NetChangeTerms.Ticks,
|
||||
_settings.row_height, _settings.price_column,
|
||||
security.ContractSpec);
|
||||
_spec);
|
||||
} else {
|
||||
LadderRender.render_prices(
|
||||
_price_vis_tup.visual, _price_vis_tup.glyph_context,
|
||||
_price_list, _settings.row_height,
|
||||
_settings.price_column, security.ContractSpec,
|
||||
_settings.price_column, _spec,
|
||||
_settings.price_display_format);
|
||||
}
|
||||
}
|
||||
@@ -1341,7 +1359,7 @@ namespace mbts.spark {
|
||||
return;
|
||||
if (_price_list is null) {
|
||||
_price_list = new LadderPriceList {
|
||||
spec = security.ContractSpec
|
||||
security = security
|
||||
};
|
||||
}
|
||||
_price_list.reset(null, null, _initial_row_count);
|
||||
@@ -1425,7 +1443,7 @@ namespace mbts.spark {
|
||||
_pending_scroll_to_origin |= _settings == null;
|
||||
_invalidate_spec();
|
||||
if (_price_list != null) {
|
||||
_price_list.spec = _spec;
|
||||
_price_list.security = security;
|
||||
}
|
||||
_bid_vis_tup.glyph_context = glyph_context(s.bid_column);
|
||||
_ask_vis_tup.glyph_context = glyph_context(s.ask_column);
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using bts.api;
|
||||
|
||||
namespace mbts.spark {
|
||||
using RegionalTickFactors = user.settings.RegionalTickFactors;
|
||||
|
||||
class LadderPriceLineViewAdapter {
|
||||
public static double bid_line(
|
||||
double bid, double ask, double settlement, ContractSpecificationImmutable? spec) {
|
||||
double bid, double ask, double settlement, RegionalTickFactors spec) {
|
||||
return TickUtils.normalize_price(spec, impl());
|
||||
double impl() {
|
||||
if (!double.IsNaN(bid)) {
|
||||
@@ -17,7 +19,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public static double ask_line(
|
||||
double bid, double ask, double settlement, ContractSpecificationImmutable? spec) {
|
||||
double bid, double ask, double settlement, RegionalTickFactors spec) {
|
||||
return TickUtils.normalize_price(spec, impl());
|
||||
double impl() {
|
||||
if (!double.IsNaN(ask)) {
|
||||
@@ -31,7 +33,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public static double mid_line(
|
||||
double bid, double ask, double settlement, ContractSpecificationImmutable? spec) {
|
||||
double bid, double ask, double settlement, RegionalTickFactors spec) {
|
||||
return TickUtils.normalize_price(spec, impl());
|
||||
double impl() {
|
||||
if (double.IsNaN(bid)) {
|
||||
@@ -43,16 +45,16 @@ namespace mbts.spark {
|
||||
if (double.IsNaN(ask)) {
|
||||
return bid;
|
||||
}
|
||||
if (spec.HasValue) {
|
||||
return TickUtils.mid_tick(spec.Value, bid, ask);
|
||||
if (spec is not null) {
|
||||
return TickUtils.mid_tick(spec, bid, ask);
|
||||
}
|
||||
return bid;
|
||||
}
|
||||
}
|
||||
|
||||
static double _try_tick_down(ContractSpecificationImmutable? spec, double value) {
|
||||
if (spec.HasValue) {
|
||||
return spec.Value.tickdown(value);
|
||||
static double _try_tick_down(RegionalTickFactors spec, double value) {
|
||||
if (spec is not null) {
|
||||
return spec.tickdown(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using bts.api;
|
||||
using bts.utils;
|
||||
|
||||
using mbts.utils;
|
||||
|
||||
@@ -8,52 +9,78 @@ using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace mbts.spark {
|
||||
using RegionalTickFactors = user.settings.RegionalTickFactors;
|
||||
public class LadderPriceList : IReadOnlyList<double>, IList<double>, INotifyCollectionChanged, IEquatable<LadderPriceList> {
|
||||
int _length;
|
||||
int _high_tick;
|
||||
const long _MAX_LENGTH = int.MaxValue;
|
||||
|
||||
long _length;
|
||||
long _high_tick;
|
||||
SecurityImmutable? _security;
|
||||
RegionalTickFactors _regional_tick_backing;
|
||||
RegionalTickFactors _regional_tick =>
|
||||
_regional_tick_backing ??= TickUtils.get_regional_ticks(_security);
|
||||
|
||||
public LadderPriceList() { }
|
||||
|
||||
public LadderPriceList(LadderPriceList other) {
|
||||
_length = other._length;
|
||||
_high_tick = other._high_tick;
|
||||
spec = other.spec;
|
||||
_security = other._security;
|
||||
}
|
||||
|
||||
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
||||
|
||||
public SecurityImmutable? security {
|
||||
get => _security;
|
||||
set {
|
||||
if (value == _security) {
|
||||
return;
|
||||
}
|
||||
_security = value;
|
||||
_regional_tick_backing = null;
|
||||
}
|
||||
}
|
||||
|
||||
public ContractSpecificationImmutable spec { get; set; }
|
||||
|
||||
public int high_tick {
|
||||
public long high_tick {
|
||||
get => _high_tick;
|
||||
set => _high_tick = value;
|
||||
}
|
||||
|
||||
public int low_tick {
|
||||
public long low_tick {
|
||||
get => high_tick - length;
|
||||
set => reset(null, value, null);
|
||||
}
|
||||
|
||||
public double start {
|
||||
get => spec.tickup(0, high_tick);
|
||||
set => high_tick = spec.tickdiff(value, 0) ?? high_tick;
|
||||
get => _regional_tick.tickup<double>(0, (uint)high_tick);
|
||||
set => high_tick = _regional_tick.tickdiff(value, 0) ?? high_tick;
|
||||
}
|
||||
|
||||
public int length {
|
||||
public long length {
|
||||
get => _length;
|
||||
set {
|
||||
if (value < 0) {
|
||||
throw new ArgumentException($"Value must be >= 0 (actually {value})");
|
||||
if (value < 0 || value > _MAX_LENGTH) {
|
||||
throw new ArgumentException(
|
||||
$"Value 'v' must be >= 0 and < {_MAX_LENGTH} (actually {value})");
|
||||
}
|
||||
_length = value;
|
||||
}
|
||||
}
|
||||
public int Count => (int)length;
|
||||
|
||||
public int Count {
|
||||
get {
|
||||
checked {
|
||||
return (int)length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public double this[int idx] {
|
||||
get => spec.tickup(0, high_tick - idx);
|
||||
get => _regional_tick.tick<double>(0, high_tick - idx);
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
@@ -67,11 +94,13 @@ namespace mbts.spark {
|
||||
GetEnumerator();
|
||||
|
||||
public int IndexOf(double item) {
|
||||
var idx = spec.tickdiff(start, item) ?? -1;
|
||||
var idx = _regional_tick.tickdiff(start, item) ?? -1;
|
||||
if (idx < 0 || idx >= length) {
|
||||
return -1;
|
||||
}
|
||||
return idx;
|
||||
checked {
|
||||
return (int)idx;
|
||||
}
|
||||
}
|
||||
|
||||
public void Insert(int index, double item) =>
|
||||
@@ -138,15 +167,15 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
public void reset(int? high_tick = null, int? low_tick = null, int? length = null) {
|
||||
public void reset(long? high_tick = null, long? low_tick = null, long? length = null) {
|
||||
if (!high_tick.HasValue && !low_tick.HasValue && !length.HasValue) {
|
||||
return;
|
||||
}
|
||||
if (length.HasValue && length.Value < 0) {
|
||||
throw new ArgumentException("Must be >= 0", nameof(length));
|
||||
}
|
||||
int new_high_tick = 0;
|
||||
int new_length = 0;
|
||||
long new_high_tick = 0;
|
||||
long new_length = 0;
|
||||
if (high_tick.HasValue) {
|
||||
new_high_tick = high_tick.Value;
|
||||
if (low_tick.HasValue) {
|
||||
@@ -180,8 +209,7 @@ namespace mbts.spark {
|
||||
other != null &&
|
||||
_high_tick == other._high_tick &&
|
||||
_length == other._length &&
|
||||
spec.LowTick.Equals(other.spec.LowTick) &&
|
||||
spec.PriceBreak.Equals(other.spec.PriceBreak);
|
||||
_regional_tick.safe_equals(other._regional_tick);
|
||||
|
||||
public override bool Equals(object obj) =>
|
||||
Equals(obj as LadderPriceList);
|
||||
@@ -189,13 +217,10 @@ namespace mbts.spark {
|
||||
public override int GetHashCode() =>
|
||||
HashCode.Combine(_high_tick, _length);
|
||||
|
||||
double _tick_to_price(int tick) =>
|
||||
spec.tickup(0, tick);
|
||||
double _tick_to_price(long tick) =>
|
||||
_regional_tick.tick<double>(0, tick);
|
||||
|
||||
int? _price_to_tick(double price) =>
|
||||
spec.tickdiff(price, 0);
|
||||
|
||||
void _add_tick(int tick) {
|
||||
void _add_tick(long tick) {
|
||||
int idx;
|
||||
if (length == 0) {
|
||||
_high_tick = tick;
|
||||
@@ -204,7 +229,9 @@ namespace mbts.spark {
|
||||
_high_tick = tick;
|
||||
idx = 0;
|
||||
} else if (tick == low_tick - 1) {
|
||||
idx = length;
|
||||
checked {
|
||||
idx = (int)length;
|
||||
}
|
||||
} else {
|
||||
throw new ArgumentException($"Must be == {nameof(high_tick)} ({high_tick}) + 1, or == {nameof(low_tick)} ({low_tick}) - 1)");
|
||||
}
|
||||
@@ -212,7 +239,7 @@ namespace mbts.spark {
|
||||
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, _tick_to_price(tick), idx));
|
||||
}
|
||||
|
||||
void _remove_tick(int tick) {
|
||||
void _remove_tick(long tick) {
|
||||
if (length == 0) {
|
||||
throw new InvalidOperationException("Cannot remove tick because length is 0");
|
||||
}
|
||||
@@ -221,7 +248,9 @@ namespace mbts.spark {
|
||||
_high_tick--;
|
||||
idx = 0;
|
||||
} else if (tick == low_tick) {
|
||||
idx = length - 1;
|
||||
checked {
|
||||
idx = (int)(length - 1);
|
||||
}
|
||||
} else {
|
||||
throw new ArgumentException(
|
||||
$"Can only remove {nameof(low_tick)} ({low_tick}) or " +
|
||||
|
||||
@@ -9,6 +9,7 @@ using mbts.ui;
|
||||
using mbts.ui.controls;
|
||||
using mbts.ui.utility.text;
|
||||
|
||||
using Spark.Core;
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
@@ -19,6 +20,8 @@ using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace mbts.spark {
|
||||
using RegionalTickFactors = user.settings.RegionalTickFactors;
|
||||
|
||||
static class BadgeRender {
|
||||
// IMPORTANT: the return values for this method MUST BE IN SYNC with the "format" method, else "measure_height" and "LadderRender.measure_row_height" will be broken.
|
||||
static int _line_count_for_style(LadderSettings.BadgeStyle badge_style) => badge_style == LadderSettings.BadgeStyle.Alternate ? 2 : 1;
|
||||
@@ -73,6 +76,16 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public static int index_of(IList<double> prices, double price, IComparer<double> comparer, bool relative_idx) {
|
||||
for (int i = 1; i < prices.Count; i++) {
|
||||
Log.assert(prices[i - 1] > prices[i]);
|
||||
var c = comparer.Compare(prices[i - 1], prices[i]);
|
||||
if (c >= 0) {
|
||||
c = comparer.Compare(prices[i - 1], prices[i]);
|
||||
} else {
|
||||
c = comparer.Compare(prices[i - 1], prices[i]);
|
||||
}
|
||||
Log.assert(c < 0);
|
||||
}
|
||||
var idx = CollectionHelper.binary_search(prices, price, comparer);
|
||||
if (relative_idx && idx < 0) {
|
||||
idx = ~idx;
|
||||
@@ -95,30 +108,13 @@ namespace mbts.spark {
|
||||
settings.font_size, settings.width, row_height, HorizontalAlignment.Right,
|
||||
-4, VerticalAlignment.Center, row * row_height, true);
|
||||
|
||||
public static IList<double> gen_prices(double mid, int row_count, ContractSpecificationImmutable spec) {
|
||||
bool is_odd = row_count % 2 == 1;
|
||||
var result = new double[row_count];
|
||||
int range = row_count / 2;
|
||||
int middle = row_count / 2;
|
||||
result[middle] = mid;
|
||||
double up = mid, down = mid;
|
||||
// Starting from the middle iterate out to the edges
|
||||
for (int x = 1; x <= range; ++x) {
|
||||
up = spec.tickup(up);
|
||||
down = spec.tickdown(down);
|
||||
result[middle - x] = up;
|
||||
result[middle + x] = down;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static GlyphRun[] format_prices(IList<double> prices, double reference_price, bool format_in_tick_terms, double row_height, LadderColumnSettings settings, GlyphContext glyph_context, ContractSpecificationImmutable spec) {
|
||||
public static GlyphRun[] format_prices(IList<double> prices, double reference_price, bool format_in_tick_terms, double row_height, LadderColumnSettings settings, GlyphContext glyph_context, RegionalTickFactors spec) {
|
||||
var result = new GlyphRun[prices.Count];
|
||||
Parallel.For(0, prices.Count, i =>
|
||||
result[i] = format_text(spec.format(prices[i] - reference_price, format_in_tick_terms), i, row_height, settings, glyph_context));
|
||||
return result;
|
||||
}
|
||||
public static GlyphRun[] format_prices(IList<double> prices, double row_height, LadderColumnSettings settings, GlyphContext glyph_context, ContractSpecificationImmutable spec, LadderSettings.PriceDisplayFormat price_display_format) {
|
||||
public static GlyphRun[] format_prices(IList<double> prices, double row_height, LadderColumnSettings settings, GlyphContext glyph_context, RegionalTickFactors spec, LadderSettings.PriceDisplayFormat price_display_format) {
|
||||
var result = new GlyphRun[prices.Count];
|
||||
Parallel.For(0, prices.Count, i =>
|
||||
result[i] = format_text(spec.format(prices[i]), i, row_height, settings, glyph_context, price_display_format));
|
||||
@@ -143,12 +139,12 @@ namespace mbts.spark {
|
||||
bool format_in_tick_terms,
|
||||
double row_height,
|
||||
LadderColumnSettings settings,
|
||||
ContractSpecificationImmutable spec) {
|
||||
RegionalTickFactors tick) {
|
||||
if (price_list.IsNullOrEmpty()) {
|
||||
return;
|
||||
}
|
||||
render_prices(
|
||||
price, glyph_context, price_list, row_height, settings, spec,
|
||||
price, glyph_context, price_list, row_height, settings, tick,
|
||||
wrt_price, format_in_tick_terms);
|
||||
}
|
||||
|
||||
@@ -158,12 +154,12 @@ namespace mbts.spark {
|
||||
IList<double> dprices,
|
||||
double row_height,
|
||||
LadderColumnSettings settings,
|
||||
ContractSpecificationImmutable spec,
|
||||
RegionalTickFactors tick,
|
||||
double wrt_price,
|
||||
bool format_in_tick_terms) {
|
||||
var foreground = settings.foreground.rgb_brush();
|
||||
//var background = new SolidColorBrush(settings.background.rgb_color());
|
||||
var fprices = format_prices(dprices, wrt_price, format_in_tick_terms, row_height, settings, glyph_context, spec);
|
||||
var fprices = format_prices(dprices, wrt_price, format_in_tick_terms, row_height, settings, glyph_context, tick);
|
||||
using (var dc = price.RenderOpen())
|
||||
using (_draw_with_clip(dc, settings, row_height, dprices.Count)) {
|
||||
//dc.DrawRectangle(background, null, new Rect(0, 0, settings.width, row_count * row_height));
|
||||
@@ -178,11 +174,11 @@ namespace mbts.spark {
|
||||
IList<double> dprices,
|
||||
double row_height,
|
||||
LadderColumnSettings settings,
|
||||
ContractSpecificationImmutable spec,
|
||||
RegionalTickFactors tick,
|
||||
LadderSettings.PriceDisplayFormat price_display_format) {
|
||||
var foreground = settings.foreground.rgb_brush();
|
||||
//var background = new SolidColorBrush(settings.background.rgb_color());
|
||||
var fprices = format_prices(dprices, row_height, settings, glyph_context, spec, price_display_format);
|
||||
var fprices = format_prices(dprices, row_height, settings, glyph_context, tick, price_display_format);
|
||||
using (var dc = price.RenderOpen())
|
||||
using (_draw_with_clip(dc, settings, row_height, dprices.Count)) {
|
||||
//dc.DrawRectangle(background, null, new Rect(0, 0, settings.width, row_count * row_height));
|
||||
@@ -215,7 +211,7 @@ namespace mbts.spark {
|
||||
IList<double> prices,
|
||||
NativePriceSize[] rungs,
|
||||
double row_height,
|
||||
ContractSpecificationImmutable spec,
|
||||
RegionalTickFactors spec,
|
||||
LadderColumnSettings settings,
|
||||
Func<NativePriceSize, string> fmt,
|
||||
bool lighten_market_cells,
|
||||
@@ -248,17 +244,18 @@ namespace mbts.spark {
|
||||
direct_size: aggr.direct_size + rung.direct_size,
|
||||
implied_size: aggr.implied_size + rung.implied_size),
|
||||
rung => {
|
||||
//spec.round_to_tick(rung.price);
|
||||
var ticks = spec.full_ticks_from_zero(rung.price);
|
||||
var ticks = spec.count_ticks(rung.price);
|
||||
return ticks.HasValue ? spec.tickup(0, ticks.Value) : rung.price;
|
||||
});
|
||||
foreach (var rung in row_tick_groups) {
|
||||
//double price = spec.round_to_tick(rung.price);
|
||||
var ticks = spec.full_ticks_from_zero(rung.price);
|
||||
var ticks = spec.count_ticks(rung.price);
|
||||
var price = ticks.HasValue ? spec.tickup(0, ticks.Value) : rung.price;
|
||||
// prices are in descending order, so get diff from curr_price - price
|
||||
int tick_diff = spec.tickdiff_unchecked(curr_price, price);
|
||||
curr_index += tick_diff;
|
||||
var tick_diff = spec.tickdiff(curr_price, price).assert_value();
|
||||
checked {
|
||||
curr_index += (int)tick_diff;
|
||||
}
|
||||
curr_price = price;
|
||||
if (curr_index >= 0 && curr_index < prices.Count) {
|
||||
if (market_cell_background_brush != null)
|
||||
@@ -278,7 +275,7 @@ namespace mbts.spark {
|
||||
IList<double> prices,
|
||||
IEnumerable<VolumeAtPriceLevelImmutable> data,
|
||||
double row_height,
|
||||
ContractSpecificationImmutable spec,
|
||||
RegionalTickFactors spec,
|
||||
VolumeColumnSettings settings,
|
||||
int last_index,
|
||||
string last_size_and_direction,
|
||||
@@ -371,7 +368,7 @@ namespace mbts.spark {
|
||||
|
||||
public delegate void RenderCell<T>(DrawingContext dc, int row, T data_item);
|
||||
|
||||
static void _render_cells<T>(DrawingVisual dv, double row_height, IEnumerable<(double price, T value)> data, LadderColumnSettings settings, IList<double> prices, ContractSpecificationImmutable spec, RenderCell<T> render_cell) {
|
||||
static void _render_cells<T>(DrawingVisual dv, double row_height, IEnumerable<(double price, T value)> data, LadderColumnSettings settings, IList<double> prices, RegionalTickFactors spec, RenderCell<T> render_cell) {
|
||||
using (var dc = dv.RenderOpen())
|
||||
using (_draw_with_clip(dc, settings, row_height, prices.Count)) {
|
||||
if (data.is_null_or_empty())
|
||||
@@ -382,8 +379,11 @@ namespace mbts.spark {
|
||||
if (double.IsNaN(price))
|
||||
continue;
|
||||
// prices are in descending order, so get diff from curr_price - price
|
||||
int tick_diff = spec.tickdiff(curr_price, price) ?? 0;
|
||||
curr_index += tick_diff;
|
||||
var tick_diff = spec.tickdiff(curr_price, price) ?? 0;
|
||||
Log.assert(
|
||||
tick_diff > (int.MaxValue - curr_index),
|
||||
$"Unable to index ladder row for price {price}: tick count exceeds int.MaxValue");
|
||||
curr_index += (int)tick_diff;
|
||||
curr_price = price;
|
||||
if (curr_index >= 0 && curr_index < prices.Count) {
|
||||
render_cell(dc, curr_index, value);
|
||||
@@ -409,7 +409,7 @@ namespace mbts.spark {
|
||||
IList<double> prices,
|
||||
IEnumerable<(double price, uint piq)> pvp,
|
||||
double row_height,
|
||||
ContractSpecificationImmutable spec,
|
||||
RegionalTickFactors spec,
|
||||
LadderColumnSettings settings,
|
||||
Func<uint, string> fmt_value) {
|
||||
//
|
||||
@@ -425,8 +425,10 @@ namespace mbts.spark {
|
||||
foreach (var entry in pvp) {
|
||||
double price = entry.price;
|
||||
// prices are in descending order, so get diff from curr_price - price
|
||||
int tick_diff = spec.tickdiff_unchecked(curr_price, price);
|
||||
curr_index += tick_diff;
|
||||
var tick_diff = spec.tickdiff(curr_price, price).assert_value();
|
||||
checked {
|
||||
curr_index += (int)tick_diff;
|
||||
}
|
||||
curr_price = price;
|
||||
if (curr_index >= 0 && curr_index < prices.Count) {
|
||||
var gr = format_text(fmt_value(entry.piq), curr_index, row_height, settings, glyph_context);
|
||||
|
||||
@@ -31,10 +31,12 @@
|
||||
ItemsSource="{Binding rows_view}"
|
||||
MinRowHeight="17"
|
||||
RowHeaderWidth="22"
|
||||
Background="{u:BTSColor ManualFills.background}"
|
||||
>
|
||||
<!--Row Header Style-->
|
||||
<DataGrid.RowHeaderStyle>
|
||||
<Style TargetType="DataGridRowHeader">
|
||||
<Setter Property="Background" Value="transparent"/>
|
||||
<Setter Property="Content" Value="{Binding}"/>
|
||||
<Setter Property="ContentTemplate">
|
||||
<Setter.Value>
|
||||
@@ -123,8 +125,12 @@
|
||||
<!--Row Style-->
|
||||
<DataGrid.RowStyle>
|
||||
<Style TargetType="DataGridRow">
|
||||
<Setter Property="Background" Value="{u:BTSColor Grid.default_row_background}"/>
|
||||
<Setter Property="IsSelected" Value="{Binding is_selected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="DataGridRow.AlternationIndex" Value="1">
|
||||
<Setter Property="Background" Value="{u:BTSColor Grid.alternate_row_background}"/>
|
||||
</Trigger>
|
||||
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource SelectedRowBackground}"/>
|
||||
</DataTrigger>
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace Spark.Trading {
|
||||
meta.Value.Value.PriceDisplay : Security.Defaults.price_display_settingsi;
|
||||
if (security.HasValue) {
|
||||
rv = rv.with(
|
||||
tick_factors: security.spec_or_default().tick_factors().to_api_tick_factors());
|
||||
tick_factors: security.Value.regional_ticks().low_tick.to_api_tick_factors());
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -891,7 +891,7 @@ namespace mbts.spark {
|
||||
};
|
||||
root_bd.SetBinding(
|
||||
Border.BackgroundProperty, new Binding(nameof(background_brush)) { Source = this });
|
||||
return button;
|
||||
return root_bd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -769,7 +769,7 @@ namespace mbts.spark {
|
||||
return;
|
||||
}
|
||||
|
||||
var price_display = row.contract_spec?.tick_factors()?.to_api_tick_display_settingsi();
|
||||
var price_display = TickUtils.get_tick(row.security, price ?? 0).to_api_tick_display_settingsi();
|
||||
var update_desc = OrderUtils.update_description(
|
||||
row.order, price, quantity, price_display, row.quantity_display_settings);
|
||||
Log.Ui.info(
|
||||
|
||||
@@ -179,8 +179,7 @@ namespace mbts.spark {
|
||||
using var _ = detect_property_changes(
|
||||
nameof(spec),
|
||||
nameof(display_quantity_divisor),
|
||||
nameof(quantity_display),
|
||||
nameof(unit_quantity));
|
||||
nameof(quantity_display));
|
||||
_security_md = value;
|
||||
bbo.security_md = value;
|
||||
_payup_bid_cmd.RaiseCanExecuteChanged();
|
||||
@@ -210,9 +209,6 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
public double unit_quantity =>
|
||||
(security?.ContractSpec)?.tick_factors()?.tick_unit_frac() ?? 1;
|
||||
|
||||
public AlgoDefinitionVM algo_vm { get; }
|
||||
public IReadOnlyObservableCollection<AlgoParamRowVM> param_rows { get; }
|
||||
public BBOVM bbo { get; }
|
||||
|
||||
@@ -231,7 +231,7 @@ namespace bts.shell {
|
||||
sorting_criteria,
|
||||
_vm.anchors,
|
||||
filters,
|
||||
state.grid.with(columns: cols, background: _vm.grid_background_color.rgb_color()),
|
||||
state.grid.with(columns: cols, background: _vm.grid_background_color.to_uint()),
|
||||
calc_type,
|
||||
_vm.header_row_display,
|
||||
menu_display: _menu_display_vm?.create());
|
||||
|
||||
@@ -68,10 +68,10 @@ namespace bts.shell.pnl {
|
||||
typeface = new TypefaceProto(
|
||||
cell_appearance.font_family?.name(),
|
||||
(cell_appearance.font_weight ?? FontWeights.Normal).ToOpenTypeWeight()),
|
||||
font_color = cell_appearance.foreground?.rgb_color() ?? 0,
|
||||
font_color = cell_appearance.foreground?.to_uint() ?? 0,
|
||||
font_size = cell_appearance.font_size,
|
||||
},
|
||||
background = cell_appearance.background?.rgb_color()
|
||||
background = cell_appearance.background?.to_uint()
|
||||
};
|
||||
|
||||
public PNLCellAppearance to_appearance() {
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -103,14 +103,14 @@ namespace bts.shell.pnl {
|
||||
public PNLAnimation to_animation(PNLView.Columns key) =>
|
||||
new PNLAnimation {
|
||||
column = key,
|
||||
foreground = is_font_color_overridden ? font_color_override.color.rgb_color() : (uint?)null,
|
||||
background = is_background_overridden ? background_override.color.rgb_color() : (uint?)null,
|
||||
foreground = is_font_color_overridden ? font_color_override.color.to_uint() : (uint?)null,
|
||||
background = is_background_overridden ? background_override.color.to_uint() : (uint?)null,
|
||||
font_weight = is_font_weight_overridden ? font_weight_override.ToOpenTypeWeight() : (int?)null
|
||||
};
|
||||
|
||||
public PNLCellAppearanceProto to_appearance_proto() =>
|
||||
new PNLCellAppearanceProto {
|
||||
background = is_background_overridden ? background_override.color.rgb_color() : (uint?)null,
|
||||
background = is_background_overridden ? background_override.color.to_uint() : (uint?)null,
|
||||
font_params = to_font_params()
|
||||
};
|
||||
|
||||
@@ -119,7 +119,7 @@ namespace bts.shell.pnl {
|
||||
typeface = new TypefaceProto(
|
||||
font_family_override?.name(),
|
||||
is_font_weight_overridden ? font_weight_override.ToOpenTypeWeight() : 0),
|
||||
font_color = is_font_color_overridden ? font_color_override.color.rgb_color() : 0,
|
||||
font_color = is_font_color_overridden ? font_color_override.color.to_uint() : 0,
|
||||
font_size = font_size_override
|
||||
};
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace bts.shell.pnl {
|
||||
// group
|
||||
var (group_cell_appearance, group_row_background_colors) = group_row_defaults.create();
|
||||
s.group_cell_appearance = PNLCellAppearanceProto.from_appearance(group_cell_appearance);
|
||||
s.group_background_colors.SetItems(group_row_background_colors.Select(c => c.rgb_color()));
|
||||
s.group_background_colors.SetItems(group_row_background_colors.Select(c => c.to_uint()));
|
||||
//
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -329,20 +329,19 @@ namespace bts.shell.pnl {
|
||||
}
|
||||
|
||||
static (string desc, Color fg) _fills_title(Columns key) {
|
||||
const uint net_fg = 0x333333u;
|
||||
switch (key) {
|
||||
case Columns.SODLongPos: return ("Open Buy Fills", BTSColors.MarketData.bid);
|
||||
case Columns.SODShortPos: return ("Open Sell Fills", BTSColors.MarketData.ask);
|
||||
case Columns.SODNetPos: return ("Open Fills", net_fg.rgb_color());
|
||||
case Columns.SODNetPos: return ("Open Fills", BTSColors.UI.default_text);
|
||||
case Columns.DayLongPos: return ("Day Buy Fills", BTSColors.MarketData.bid);
|
||||
case Columns.DayShortPos: return ("Day Sell Fills", BTSColors.MarketData.ask);
|
||||
case Columns.DayNetPos: return ("Day Fills", net_fg.rgb_color());
|
||||
case Columns.DayNetPos: return ("Day Fills", BTSColors.UI.default_text);
|
||||
case Columns.RawDayLongPos: return ("Raw Day Buy Fills", BTSColors.MarketData.bid);
|
||||
case Columns.RawDayShortPos: return ("Raw Day Sell Fills", BTSColors.MarketData.ask);
|
||||
case Columns.RawDayNetPos: return ("Raw Day Fills", net_fg.rgb_color());
|
||||
case Columns.RawDayNetPos: return ("Raw Day Fills", BTSColors.UI.default_text);
|
||||
case Columns.TotalLongPos: return ("All Buy Fills", BTSColors.MarketData.bid);
|
||||
case Columns.TotalShortPos: return ("All Sell Fills", BTSColors.MarketData.ask);
|
||||
case Columns.TotalNetPos: return ("All Fills", net_fg.rgb_color());
|
||||
case Columns.TotalNetPos: return ("All Fills", BTSColors.UI.default_text);
|
||||
default: throw ExceptionBuilder.Argument.unexpected_case(key, nameof(key));
|
||||
}
|
||||
}
|
||||
@@ -368,7 +367,7 @@ namespace bts.shell.pnl {
|
||||
switch (key) {
|
||||
case Columns.WorkingLongPos: return ("Working Buy Orders", BTSColors.MarketData.bid);
|
||||
case Columns.WorkingShortPos: return ("Working Sell Orders", BTSColors.MarketData.ask);
|
||||
case Columns.WorkingNetPos: return ("Working Orders", 0x333333u.rgb_color());
|
||||
case Columns.WorkingNetPos: return ("Working Orders", BTSColors.UI.default_text);
|
||||
default: throw ExceptionBuilder.Argument.unexpected_case(key, nameof(key));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using BCG;
|
||||
|
||||
namespace mbts.ui {
|
||||
public class NMSheetAllTaskingData {
|
||||
public IDictionary<UInt32, NMSheetTaskEyeData>
|
||||
bids = new Dictionary<UInt32, NMSheetTaskEyeData>(),
|
||||
asks = new Dictionary<UInt32, NMSheetTaskEyeData>();
|
||||
public void add_sec(UInt32 sec, bts.api.Side side, double edge, double size) {
|
||||
IDictionary<UInt32, NMSheetTaskEyeData> map = side == bts.api.Side.Buy ? bids : asks;
|
||||
NMSheetTaskEyeData sec_data;
|
||||
if (!map.TryGetValue(sec, out sec_data)) {
|
||||
sec_data = new NMSheetTaskEyeData(true, edge, size);
|
||||
map.Add(sec, sec_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using mbts.ui;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -17,7 +19,7 @@ namespace BCG
|
||||
private readonly IDictionary<NMSheetSymbol, NMSheetSingleOptionData> _sym_data_map;
|
||||
private readonly IDictionary<NMSheetSymbol, IDictionary<uint, BBOPacket>> _bbo_map;
|
||||
private readonly IDictionary<uint, NMSheetTickerData> _complete_ticker_data;
|
||||
private readonly TaskingConsolidatedData _task_data;
|
||||
private readonly NMSheetAllTaskingData _task_data;
|
||||
|
||||
private readonly double[] _cached_sorted_strikes;
|
||||
private readonly NMSheetExpiration[] _cached_sorted_expirations;
|
||||
@@ -27,7 +29,7 @@ namespace BCG
|
||||
public NMSheetData(IDictionary<NMSheetSymbol, NMSheetSingleOptionData> sym_data_map,
|
||||
IDictionary<NMSheetSymbol, IDictionary<uint, BBOPacket>> bbo_map,
|
||||
IDictionary<uint, NMSheetTickerData> complete_ticker_data,
|
||||
TaskingConsolidatedData task_data)
|
||||
NMSheetAllTaskingData task_data)
|
||||
{
|
||||
_sym_data_map = sym_data_map;
|
||||
_bbo_map = bbo_map;
|
||||
@@ -61,14 +63,14 @@ namespace BCG
|
||||
|
||||
public NMSheetData filter_for_strikes_in_tasks(bool is_on_only = false)
|
||||
{
|
||||
if (_task_data != null)
|
||||
{
|
||||
IEnumerable<uint> eye_secs = _task_data.get_set_securities(mbts.tasks.TaskType.Eye, is_on_only),
|
||||
quoter_secs = _task_data.get_set_securities(mbts.tasks.TaskType.Quoter, is_on_only);
|
||||
HashSet<uint> all_secs = new HashSet<uint>(Enumerable.Concat(eye_secs, quoter_secs));
|
||||
return filter_data(this, all_secs);
|
||||
}
|
||||
else
|
||||
// if (_task_data != null)
|
||||
// {
|
||||
// IEnumerable<uint> eye_secs = _task_data.get_set_securities(mbts.tasks.TaskType.Eye, is_on_only),
|
||||
// quoter_secs = _task_data.get_set_securities(mbts.tasks.TaskType.Quoter, is_on_only);
|
||||
// HashSet<uint> all_secs = new HashSet<uint>(Enumerable.Concat(eye_secs, quoter_secs));
|
||||
// return filter_data(this, all_secs);
|
||||
// }
|
||||
// else
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -104,9 +106,7 @@ namespace BCG
|
||||
return symbol_data.get_security_key(exp.option_expiration, strike, is_call, out security_key);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public TaskingConsolidatedData get_task_data() { return _task_data; }
|
||||
}
|
||||
|
||||
#region INMSheetGridFacingData
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ namespace BCG {
|
||||
private readonly IDictionary<DateTime, Tuple<double, double>> _option_exp_driver_detailed_price_data = new Dictionary<DateTime, Tuple<double, double>>();
|
||||
private IDictionary<uint, BBOPacket> _bbo_data_map = new Dictionary<uint, BBOPacket>();
|
||||
private IDictionary<uint, NMSheetTickerData> _ticker_data = new Dictionary<uint, NMSheetTickerData>();
|
||||
private TaskingConsolidatedData _tasking_data;
|
||||
private readonly ExchangeSecurityMap _sec_map;
|
||||
private NMSheetAllTaskingData _ee_tasking_data = new NMSheetAllTaskingData();
|
||||
|
||||
public NMSheetSingleOptionData(NMSheetSymbol option,
|
||||
NMSheetDataRequest data_request,
|
||||
@@ -93,7 +93,7 @@ namespace BCG {
|
||||
|
||||
public void set_ticker(IDictionary<uint, NMSheetTickerData> ticker_data) { _ticker_data = ticker_data; }
|
||||
|
||||
public void set_task_data(TaskingConsolidatedData tasking_data) { _tasking_data = tasking_data; }
|
||||
public void set_task_data(NMSheetAllTaskingData tasking_data) { _ee_tasking_data = tasking_data; }
|
||||
|
||||
/// Strikes are not sorted
|
||||
public double[] get_strikes() { return _theo_data_map.get_strikes(); }
|
||||
@@ -128,7 +128,7 @@ namespace BCG {
|
||||
_fill_roll_over_data(cp_row, v, expiration, strike);
|
||||
_fill_presave_theos(cp_row, v, expiration, strike);
|
||||
NMSheetCallPutBidAskWrapper<NMSheetTaskEyeData> eye_data;
|
||||
_fill_eye_data(tp_with_seckey, driver_bid_ask, call_bbo_packet, put_bbo_packet, ref cp_row, out eye_data);
|
||||
_fill_eye_data(tp_with_seckey, ref cp_row, out eye_data);
|
||||
NMSheetCallPutBidAskWrapper<NMSheetTaskQuoterData> quoter_data;
|
||||
_fill_quoter_data(tp_with_seckey, driver_bid_ask, cp_row, out quoter_data);
|
||||
NMSheetTickerData c_trade_data, p_ticker_data;
|
||||
|
||||
@@ -3,45 +3,32 @@
|
||||
using bts.api;
|
||||
|
||||
using mbts.spark;
|
||||
using mbts.ui;
|
||||
|
||||
namespace BCG {
|
||||
public partial class NMSheetSingleOptionData {
|
||||
private void _fill_eye_data(Triplet<mbts.spark.TheoPoint, uint, uint> tp_with_seckeys, Tuple<double, double> driver_bid_ask, BBOPacket call_bbo, BBOPacket put_bbo,
|
||||
ref double[] cp_row, out NMSheetCallPutBidAskWrapper<NMSheetTaskEyeData> out_eye_data) {
|
||||
// Gets the data from the bus, and fills in out_eye_data, and cp_row
|
||||
private void _fill_eye_data(Triplet<mbts.spark.TheoPoint, uint, uint> tp_with_seckeys,
|
||||
ref double[] cp_row,
|
||||
out NMSheetCallPutBidAskWrapper<NMSheetTaskEyeData> out_eye_data) {
|
||||
NMSheetTaskEyeData call_bid_data, call_ask_data, put_bid_data, put_ask_data;
|
||||
_get_eye_security_side_data(tp_with_seckeys.first, PutOrCall.Call, Side.Buy, tp_with_seckeys.second, driver_bid_ask, call_bbo, out call_bid_data, ref cp_row,
|
||||
NMSheetColumnName.call_ee_set_bid_edge, NMSheetColumnName.call_ee_set_bid_size, NMSheetColumnName.call_ee_bid_price);
|
||||
_get_eye_security_side_data(tp_with_seckeys.first, PutOrCall.Call, Side.Sell, tp_with_seckeys.second, driver_bid_ask, call_bbo, out call_ask_data, ref cp_row,
|
||||
NMSheetColumnName.call_ee_set_ask_edge, NMSheetColumnName.call_ee_set_ask_size, NMSheetColumnName.call_ee_ask_price);
|
||||
_get_eye_security_side_data(tp_with_seckeys.first, PutOrCall.Put, Side.Buy, tp_with_seckeys.third, driver_bid_ask, put_bbo, out put_bid_data, ref cp_row,
|
||||
NMSheetColumnName.put_ee_set_bid_edge, NMSheetColumnName.put_ee_set_bid_size, NMSheetColumnName.put_ee_bid_price);
|
||||
_get_eye_security_side_data(tp_with_seckeys.first, PutOrCall.Put, Side.Sell, tp_with_seckeys.third, driver_bid_ask, put_bbo, out put_ask_data, ref cp_row,
|
||||
NMSheetColumnName.put_ee_set_ask_edge, NMSheetColumnName.put_ee_set_ask_size, NMSheetColumnName.put_ee_ask_price);
|
||||
out_eye_data = new NMSheetCallPutBidAskWrapper<NMSheetTaskEyeData>(call_bid_data, call_ask_data, put_bid_data, put_ask_data);
|
||||
// call
|
||||
_get_eye_security_side_data(tp_with_seckeys.second, Side.Buy, out call_bid_data);
|
||||
_get_eye_security_side_data(tp_with_seckeys.second, Side.Sell, out call_ask_data);
|
||||
// put
|
||||
_get_eye_security_side_data(tp_with_seckeys.third, Side.Buy, out put_bid_data);
|
||||
_get_eye_security_side_data(tp_with_seckeys.third, Side.Sell, out put_ask_data);
|
||||
out_eye_data = new NMSheetCallPutBidAskWrapper<NMSheetTaskEyeData>(
|
||||
call_bid_data, call_ask_data, put_bid_data, put_ask_data);
|
||||
}
|
||||
|
||||
private void _get_eye_security_side_data(mbts.spark.TheoPoint tp, PutOrCall cp, Side side, uint sec_key, Tuple<double, double> driver_bid_ask, BBOPacket bbo,
|
||||
out NMSheetTaskEyeData inp_out_data,
|
||||
ref double[] out_array,
|
||||
NMSheetColumnName inp_edge_col, NMSheetColumnName inp_size_col, NMSheetColumnName eye_price_col) {
|
||||
mbts.tasks.TaskSecurityEyeData eye_data = _tasking_data.get_eye_data(sec_key, side);
|
||||
double edge = Double.NaN, eye_price = Double.NaN;
|
||||
uint size = 0;
|
||||
if (eye_data != null) {
|
||||
edge = eye_data.edge;
|
||||
size = eye_data.size;
|
||||
/// Why is the eye sending the price instead of theo ?
|
||||
if (eye_data.is_on)
|
||||
eye_price = eye_data.eye_published_price;
|
||||
else {
|
||||
double theo = _compute_theo(tp, cp, side, driver_bid_ask);
|
||||
eye_price = Math.Max(0.0, side == Side.Buy ? theo - edge : theo + edge);
|
||||
}
|
||||
}
|
||||
out_array[(int)inp_edge_col] = edge;
|
||||
out_array[(int)inp_size_col] = (double)size;
|
||||
out_array[(int)eye_price_col] = eye_price;
|
||||
inp_out_data = new NMSheetTaskEyeData(eye_data, side == Side.Buy ? eye_price >= BBOPacket.get_ask_price(bbo) : eye_price <= BBOPacket.get_bid_price(bbo));
|
||||
private void _get_eye_security_side_data(uint sec_key, Side side,
|
||||
out NMSheetTaskEyeData inp_out_data) {
|
||||
inp_out_data = null;
|
||||
if (_ee_tasking_data == null)
|
||||
return;
|
||||
var map = side == Side.Buy ? _ee_tasking_data.bids : _ee_tasking_data.asks;
|
||||
map.TryGetValue(sec_key, out inp_out_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using bts.api;
|
||||
|
||||
using mbts;
|
||||
using mbts.spark;
|
||||
using BCG;
|
||||
using System.Collections;
|
||||
using mbts.analytics;
|
||||
using bts.api.analytics;
|
||||
using System.Reactive.Linq;
|
||||
using bts.api.orderman;
|
||||
|
||||
namespace mbts.ui {
|
||||
internal class NMSheetAllTaskingDataSource {
|
||||
private IBus _bus;
|
||||
HighPerformanceTimer _timer = new HighPerformanceTimer();
|
||||
|
||||
private Nullable<DynamicOrderDefinitionImmutable> get_tasking_order(
|
||||
OrderDefinitionImmutable def) {
|
||||
if (def.HasCustomDef && def.CustomDef.HasComposite &&
|
||||
def.CustomDef.Composite.HasDefinition &&
|
||||
def.CustomDef.Composite.Definition.HasDynamic) {
|
||||
var dyn = def.CustomDef.Composite.Definition.Dynamic;
|
||||
if ("Tasking Eye".Equals(dyn.DynamicOrderType)) {
|
||||
return dyn;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool is_working(OrderStatus status) {
|
||||
return status == OrderStatus.Working ||
|
||||
status == OrderStatus.PendingWorking ||
|
||||
status == OrderStatus.Disconnected;
|
||||
}
|
||||
|
||||
private void add_task_secs(ref NMSheetAllTaskingData t_data,
|
||||
bts.api.Side side,
|
||||
DynamicOrderDefinitionImmutable t_order) {
|
||||
DynamicOrderParam sec_p;
|
||||
if (t_order.OrderParams.TryGetValue("Securities", out sec_p)) {
|
||||
if (!String.IsNullOrEmpty(sec_p.AsString)) {
|
||||
DynamicOrderParam edge_param = null;
|
||||
t_order.OrderParams.TryGetValue("Edge", out edge_param);
|
||||
DynamicOrderParam size_param = null;
|
||||
t_order.OrderParams.TryGetValue("Shot Size", out size_param);
|
||||
if (edge_param != null && size_param != null) {
|
||||
var toks = sec_p.AsString.Split(',');
|
||||
foreach (var s in toks) {
|
||||
UInt32 sec_key;
|
||||
if (UInt32.TryParse(s.Trim(), out sec_key)) {
|
||||
t_data.add_sec(sec_key, side, edge_param.AsDouble, size_param.AsDouble);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public NMSheetAllTaskingDataSource(OrdersModel orders_model, IBus bus) {
|
||||
bts.Log.Gen.info("NMSheetAllTaskingDataSource constructed");
|
||||
_bus = bus;
|
||||
orders_model.on_orders.Subscribe(ords => {
|
||||
_timer.start();
|
||||
NMSheetAllTaskingData t_data = new NMSheetAllTaskingData();
|
||||
bts.Log.Gen.info($"NMSheetAllTaskingDataSource on_orders n_orders: {ords.state.Values.Count()}");
|
||||
foreach (var k in ords.state.Values) {
|
||||
OrderRecordImmutable order = k.order;
|
||||
if (!is_working(order.State.Status))
|
||||
continue;
|
||||
var t_dyn = get_tasking_order(order.Def);
|
||||
if (t_dyn.HasValue) {
|
||||
add_task_secs(ref t_data, order.Def.Side, t_dyn.Value);
|
||||
}
|
||||
}
|
||||
_timer.stop();
|
||||
bts.Log.Gen.info($"NMSheetAllTaskingDataSource n_bids: {t_data.bids.Count()} " +
|
||||
$"n_asks: {t_data.asks.Count()} t_msecs: {_timer.lastIntervalTime}");
|
||||
bus.post(SparkTags.TC2Tags.TaskData, t_data);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,12 +95,13 @@ namespace BCG {
|
||||
}
|
||||
|
||||
public class NMSheetTaskEyeData {
|
||||
public readonly mbts.tasks.TaskSecurityEyeData eye_data;
|
||||
public readonly bool is_eye_cross;
|
||||
public readonly bool is_on;
|
||||
public readonly double edge, size;
|
||||
|
||||
public NMSheetTaskEyeData(mbts.tasks.TaskSecurityEyeData eye_data, bool is_eye_cross) {
|
||||
this.eye_data = eye_data;
|
||||
this.is_eye_cross = is_eye_cross;
|
||||
public NMSheetTaskEyeData(bool is_on, double edge, double size) {
|
||||
this.is_on = is_on;
|
||||
this.edge = edge;
|
||||
this.size = size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
||||
using bts.api;
|
||||
|
||||
using mbts.spark;
|
||||
using mbts.ui;
|
||||
|
||||
namespace BCG {
|
||||
public class NMSheetDataCoalescer : IDisposable {
|
||||
@@ -31,12 +32,12 @@ namespace BCG {
|
||||
_bbo_data_source = new NMSheetBBODataSource(threaded_bb, nmsheet_symbol_list, () => { _is_dirty = true; });
|
||||
_ticker_data_source = new NMSheetTickerDataSource(threaded_bb, nmsheet_symbol_list, req_id, () => { _is_dirty = true; });
|
||||
_presaved_theos_provider = new NMSheetPresavedTheosProvider(threaded_bb, nmsheet_symbol_list, req_id);
|
||||
//_threaded_bb.add_to_subscription_list(TaskingTags.ConsolidatedDataTag);
|
||||
_threaded_bb.subscribe(SparkTags.TC2Tags.TaskData);
|
||||
_threaded_bb.data_callback += _on_bb_update;
|
||||
}
|
||||
|
||||
private void _on_bb_update(object tag, object data) {
|
||||
if (/*TaskingTags.ConsolidatedDataTag.Equals(tag) ||*/ _in_bb_settings_tag.Equals(tag))
|
||||
if (SparkTags.TC2Tags.TaskData.Equals(tag) || _in_bb_settings_tag.Equals(tag))
|
||||
_is_dirty = true;
|
||||
}
|
||||
|
||||
@@ -44,9 +45,9 @@ namespace BCG {
|
||||
if (_is_dirty) {
|
||||
_is_dirty = false;
|
||||
_timer.start();
|
||||
TaskingConsolidatedData d = null;//_threaded_bb.sec_thread_retrieve_from_cache (TaskingTags.ConsolidatedDataTag) as TaskingConsolidatedData;
|
||||
NMSheetData rv = new NMSheetData(_main_data_source.get_data(), _bbo_data_source.get_all_data(), _ticker_data_source.get_data(),
|
||||
d ?? TaskingConsolidatedData.empty);
|
||||
NMSheetAllTaskingData d = _threaded_bb.read_state(
|
||||
SparkTags.TC2Tags.TaskData, new NMSheetAllTaskingData());
|
||||
NMSheetData rv = new NMSheetData(_main_data_source.get_data(), _bbo_data_source.get_all_data(), _ticker_data_source.get_data(), d);
|
||||
rv = _filter_data(rv, _threaded_bb.read_state(_in_bb_settings_tag));
|
||||
_timer.stop();
|
||||
_stats_logger.log(String.Format("NMSheetDataCoalescer_{0}", _req_id), "NMSheetData.cons", _timer.lastIntervalTime);
|
||||
|
||||
@@ -58,5 +58,10 @@ namespace BCG {
|
||||
public static UInt32 get_ask_size(BBOPacket md) {
|
||||
return md != null ? md._ask_size : (UInt32)0;
|
||||
}
|
||||
public static Tuple<double, UInt32> get_md(BBOPacket md, bool is_bid) {
|
||||
double price = is_bid ? BBOPacket.get_bid_price(md) : BBOPacket.get_ask_price(md);
|
||||
UInt32 sz = is_bid ? BBOPacket.get_bid_size(md) : BBOPacket.get_ask_size(md);
|
||||
return Tuple.Create(price, sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
|
||||
namespace mbts.tasks {
|
||||
[ProtoContract(Name = "ElectronicTradingTask")]
|
||||
[Serializable]
|
||||
public class ElectronicTradingTask {
|
||||
[ProtoBuf.ProtoMember(10)]
|
||||
public readonly TaskCommon common = null;
|
||||
[ProtoBuf.ProtoMember(20)]
|
||||
public readonly ExplicitTask explicit_task = null;
|
||||
[ProtoBuf.ProtoMember(30)]
|
||||
public readonly ImplicitTask implicit_task = null;
|
||||
|
||||
private ElectronicTradingTask() { }
|
||||
|
||||
public ElectronicTradingTask(TaskCommon common, ExplicitTask task) {
|
||||
// Logger.assert(common != null);
|
||||
// Logger.assert(task != null);
|
||||
this.common = common;
|
||||
this.explicit_task = task;
|
||||
this.implicit_task = null;
|
||||
}
|
||||
public ElectronicTradingTask(TaskCommon common, ImplicitTask task) {
|
||||
// Logger.assert(common != null);
|
||||
// Logger.assert(task != null);
|
||||
this.common = common;
|
||||
this.explicit_task = null;
|
||||
this.implicit_task = task;
|
||||
}
|
||||
|
||||
public ElectronicTradingTask with(TaskCommon common) {
|
||||
return explicit_task == null ?
|
||||
new ElectronicTradingTask(common, implicit_task) :
|
||||
new ElectronicTradingTask(common, explicit_task);
|
||||
}
|
||||
public ElectronicTradingTask with(TaskCommon common = null, ExplicitTask explicit_task = null) {
|
||||
return new ElectronicTradingTask(common ?? this.common, explicit_task ?? this.explicit_task);
|
||||
}
|
||||
public ElectronicTradingTask with(TaskCommon common = null, ImplicitTask implicit_task = null) {
|
||||
return new ElectronicTradingTask(common ?? this.common, explicit_task ?? this.explicit_task);
|
||||
}
|
||||
public override string ToString() {
|
||||
return common.id;
|
||||
}
|
||||
}
|
||||
|
||||
public class QuickStartElectronicTradingTask {
|
||||
private readonly ElectronicTradingTask _task;
|
||||
public QuickStartElectronicTradingTask(TaskCommon common, ExplicitTask task) {
|
||||
_task = new ElectronicTradingTask(common, task);
|
||||
}
|
||||
public static implicit operator ElectronicTradingTask(QuickStartElectronicTradingTask task) {
|
||||
return task._task;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
|
||||
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace mbts.tasks {
|
||||
[Serializable]
|
||||
//[RecordType]
|
||||
[ProtoContract(Name = "TaskCommon")]
|
||||
public class TaskCommon {
|
||||
[ProtoMember(1)]
|
||||
public readonly string session;
|
||||
[ProtoMember(10)]
|
||||
public readonly string id;
|
||||
[ProtoMember(20)]
|
||||
public readonly DateTime create_time;
|
||||
[ProtoMember(30)]
|
||||
public readonly TaskType task_type;
|
||||
[ProtoMember(40)]
|
||||
public readonly string name;
|
||||
[ProtoMember(50)]
|
||||
public readonly TaskEdgeType edge_type;
|
||||
[ProtoMember(60)]
|
||||
public readonly string edge_surface;
|
||||
[ProtoMember(70)]
|
||||
public readonly double bid_edge_param;
|
||||
[ProtoMember(75)]
|
||||
public readonly double ask_edge_param;
|
||||
[ProtoMember(80)]
|
||||
public readonly double bid_size_param;
|
||||
[ProtoMember(85)]
|
||||
public readonly double ask_size_param;
|
||||
[ProtoMember(90)]
|
||||
public readonly TaskExitCondition exit_condition;
|
||||
[ProtoMember(100)]
|
||||
public readonly double exit_condition_parameter;
|
||||
[ProtoMember(110)]
|
||||
public readonly bool rfq_only;
|
||||
[ProtoMember(120)]
|
||||
public readonly double rfq_quote_for_seconds;
|
||||
[ProtoMember(130)]
|
||||
public readonly TaskSide side;
|
||||
[ProtoMember(140)]
|
||||
public readonly DateTime last_modification_time;
|
||||
[ProtoMember(150)]
|
||||
public readonly bool auto_hedge;
|
||||
//[ProtoMember(160)]
|
||||
//public readonly bool auto_start;
|
||||
[ProtoMember(200)]
|
||||
public readonly List<Tuple<int, double>> overridden_edges;
|
||||
[ProtoMember(210)]
|
||||
public readonly List<Tuple<int, uint>> overridden_sizes;
|
||||
|
||||
private TaskCommon() { /*for protobuf*/ }
|
||||
|
||||
public TaskCommon(string id,
|
||||
string session,
|
||||
DateTime create_time,
|
||||
TaskType task_type,
|
||||
string task_name,
|
||||
TaskExitCondition exit_condition,
|
||||
double exit_condition_param,
|
||||
bool rfq_only,
|
||||
double rfq_quote_for_seconds,
|
||||
TaskEdgeType edge_type,
|
||||
string edge_surface,
|
||||
double bid_edge_param,
|
||||
double ask_edge_param,
|
||||
double bid_size_param,
|
||||
double ask_size_param,
|
||||
TaskSide side,
|
||||
DateTime last_modification_time,
|
||||
bool auto_hedge,
|
||||
List<Tuple<int, double>> overridden_edges,
|
||||
List<Tuple<int, uint>> overridden_sizes) {
|
||||
this.id = id;
|
||||
this.session = session;
|
||||
this.create_time = create_time;
|
||||
this.task_type = task_type;
|
||||
this.name = task_name;
|
||||
this.exit_condition = exit_condition;
|
||||
this.exit_condition_parameter = exit_condition_param;
|
||||
this.rfq_only = rfq_only;
|
||||
this.rfq_quote_for_seconds = rfq_quote_for_seconds;
|
||||
this.edge_type = edge_type;
|
||||
this.edge_surface = edge_surface;
|
||||
this.bid_edge_param = bid_edge_param;
|
||||
this.ask_edge_param = ask_edge_param;
|
||||
this.bid_size_param = bid_size_param;
|
||||
this.ask_size_param = ask_size_param;
|
||||
this.side = side;
|
||||
this.last_modification_time = last_modification_time;
|
||||
this.auto_hedge = auto_hedge;
|
||||
this.overridden_edges = overridden_edges;
|
||||
this.overridden_sizes = overridden_sizes;
|
||||
}
|
||||
|
||||
public static TaskCommon Default {
|
||||
get {
|
||||
return new TaskCommon(
|
||||
id: Guid.NewGuid().ToString(),
|
||||
session: String.Empty,
|
||||
create_time: DateTime.Now,
|
||||
task_type: TaskType.Quoter,
|
||||
task_name: "",
|
||||
exit_condition: TaskExitCondition.Contracts,
|
||||
exit_condition_param: 100,
|
||||
rfq_only: false,
|
||||
rfq_quote_for_seconds: 10,
|
||||
edge_type: TaskEdgeType.Manual,
|
||||
edge_surface: "",
|
||||
bid_edge_param: double.NaN,
|
||||
ask_edge_param: double.NaN,
|
||||
bid_size_param: double.NaN,
|
||||
ask_size_param: double.NaN,
|
||||
side: TaskSide.Buy | TaskSide.Sell,
|
||||
last_modification_time: DateTime.Now,
|
||||
auto_hedge: true,
|
||||
overridden_edges: new List<Tuple<int, double>>(),
|
||||
overridden_sizes: new List<Tuple<int, uint>>());
|
||||
}
|
||||
}
|
||||
|
||||
public TaskCommon with(string id = null, string session = null, DateTime? create_time = null,
|
||||
TaskType? task_type = null, string name = null, TaskExitCondition? exit_condition = null,
|
||||
double? exit_condition_parameter = null, bool? rfq_only = null, double? rfq_quote_for_seconds = null, TaskEdgeType? edge_type = null,
|
||||
string edge_surface = null,
|
||||
double? bid_edge_param = null, double? bid_size_param = null,
|
||||
double? ask_edge_param = null, double? ask_size_param = null,
|
||||
TaskSide? side = null, DateTime? last_modification_time = null,
|
||||
bool? auto_hedge = null,
|
||||
List<Tuple<int, double>> overridden_edges = null,
|
||||
List<Tuple<int, uint>> overridden_sizes = null) {
|
||||
return new TaskCommon(id ?? this.id,
|
||||
session ?? this.session,
|
||||
create_time ?? this.create_time,
|
||||
task_type ?? this.task_type,
|
||||
name ?? this.name,
|
||||
exit_condition ?? this.exit_condition,
|
||||
exit_condition_parameter ?? this.exit_condition_parameter,
|
||||
rfq_only ?? this.rfq_only,
|
||||
rfq_quote_for_seconds ?? this.rfq_quote_for_seconds,
|
||||
edge_type ?? this.edge_type,
|
||||
edge_surface ?? this.edge_surface,
|
||||
bid_edge_param ?? this.bid_edge_param,
|
||||
ask_edge_param ?? this.ask_edge_param,
|
||||
bid_size_param ?? this.bid_size_param,
|
||||
ask_size_param ?? this.ask_size_param,
|
||||
side ?? this.side,
|
||||
last_modification_time ?? this.last_modification_time,
|
||||
auto_hedge ?? this.auto_hedge,
|
||||
overridden_edges ?? this.overridden_edges,
|
||||
overridden_sizes ?? this.overridden_sizes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace mbts.tasks
|
||||
{
|
||||
/// Task persisted state combined with
|
||||
/// the live running state
|
||||
public class TaskLiveData : IEquatable<TaskLiveData>
|
||||
{
|
||||
public readonly ElectronicTradingTask task;
|
||||
public readonly TaskSwitchState switch_state;
|
||||
public readonly TaskHealthState task_state;
|
||||
public readonly double net_accumulation, abs_accumulation;
|
||||
|
||||
public TaskLiveData(ElectronicTradingTask task, TaskSwitchState switch_state, TaskHealthState health_state,
|
||||
double net_accumulation, double abs_accumulation)
|
||||
{
|
||||
this.task = task;
|
||||
this.switch_state = switch_state;
|
||||
this.task_state = health_state;
|
||||
this.net_accumulation = net_accumulation;
|
||||
this.abs_accumulation = abs_accumulation;
|
||||
}
|
||||
|
||||
public string task_id { get { return task.common.id; } }
|
||||
|
||||
public TaskType task_type { get { return task.common.task_type; } }
|
||||
|
||||
public string name { get { return task.common.name; } }
|
||||
|
||||
public double completion_ratio { get { return abs_accumulation / task.common.exit_condition_parameter; } }
|
||||
|
||||
public bool is_filled { get { return completion_ratio >= 1.0; } }
|
||||
|
||||
public DateTime modification_time { get { return task.common.last_modification_time; } }
|
||||
|
||||
public TaskLiveData with(ElectronicTradingTask task = null, TaskSwitchState? switch_state = null, TaskHealthState? task_state = null,
|
||||
double? net_accumulation = null, double? abs_accumulation = null)
|
||||
{
|
||||
return new TaskLiveData(task ?? this.task,
|
||||
switch_state ?? this.switch_state,
|
||||
task_state ?? this.task_state,
|
||||
net_accumulation ?? this.net_accumulation,
|
||||
abs_accumulation ?? this.abs_accumulation);
|
||||
}
|
||||
|
||||
public int GetHashCode(TaskLiveData obj) { return obj.task_id.GetHashCode(); }
|
||||
|
||||
public bool Equals(TaskLiveData other)
|
||||
{
|
||||
return ReferenceEquals(task, other.task) &&
|
||||
switch_state == other.switch_state &&
|
||||
task_state == other.task_state &&
|
||||
completion_ratio == other.completion_ratio;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return task.ToString();
|
||||
}
|
||||
|
||||
public string get_summary_text()
|
||||
{
|
||||
string sign = task.common.side == TaskSide.Buy ? "+" : (task.common.side == TaskSide.Sell ? "-" : "+/-");
|
||||
return String.Format("{0}{1} ({2}/{3})", sign, task.common.name, abs_accumulation, task.common.exit_condition_parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace mbts.tasks {
|
||||
public class TaskSecurityEyeData {
|
||||
|
||||
public TaskSecurityEyeData() {
|
||||
}
|
||||
|
||||
public bool is_output_present {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool is_on {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// If the security is on, returns the edge as sent by the eye
|
||||
/// otherwise returns the input edge
|
||||
public double edge {
|
||||
get {
|
||||
return Double.NaN;
|
||||
}
|
||||
}
|
||||
|
||||
/// If the security is on, returns the size as sent by the eye
|
||||
/// otherwise returns the input size
|
||||
public uint size {
|
||||
get {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public double eye_published_price {
|
||||
get {
|
||||
// if (is_on && is_output_present)
|
||||
// return input.secside_key.side == bts.o2.msgs.Side.type.BUY ? output.price - output.edge : output.price + output.edge;
|
||||
// return Double.NaN;
|
||||
return Double.NaN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,53 +48,3 @@ namespace mbts.engine {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace BCG {
|
||||
public class TaskingConsolidatedData {
|
||||
public TaskingConsolidatedData(IEnumerable<TaskLiveData> input_tasks,
|
||||
object input_securities,
|
||||
object eye_output,
|
||||
object quoter_output) {
|
||||
}
|
||||
public readonly static TaskingConsolidatedData empty = new TaskingConsolidatedData(Enumerable.Empty<TaskLiveData>(),
|
||||
null, null, null);
|
||||
// public TaskingConsolidatedData with(IEnumerable<TaskLiveData> input_tasks = null,
|
||||
// IEnumerable<TaskSecurityData> input_securities = null,
|
||||
// IEnumerable<EyeSecurityState> eye_output = null,
|
||||
// IEnumerable<QuoterSecurityState> quoter_output = null) {
|
||||
// return new TaskingConsolidatedData(input_tasks ?? this._input_tasks, input_securities ?? this._input_securities,
|
||||
// eye_output ?? _eye_output, quoter_output ?? _quoter_output);
|
||||
// }
|
||||
|
||||
public IEnumerable<TaskLiveData> get_tasks(TaskType task_type) { return new TaskLiveData[] { }; }
|
||||
|
||||
public TaskLiveData get_task_by_name(TaskType task_type, string name) {
|
||||
IEnumerable<TaskLiveData> live_tasks = get_tasks(task_type);
|
||||
return live_tasks.FirstOrDefault(lt => lt.task.common.name == name);
|
||||
}
|
||||
|
||||
public IEnumerable<TaskLiveData> get_security_owning_tasks(IEnumerable<SecuritySideKey> secside_keys, TaskType t_type) {
|
||||
HashSet<TaskLiveData> rv = new HashSet<TaskLiveData>();
|
||||
return rv;
|
||||
}
|
||||
|
||||
public HashSet<uint> get_set_securities(TaskType task_type, bool is_on_only = false) {
|
||||
return new HashSet<uint>();
|
||||
}
|
||||
|
||||
public TaskSecurityEyeData get_eye_data(uint key, Side side) { return get_eye_data(new SecuritySideKey(key, side)); }
|
||||
public TaskSecurityEyeData get_eye_data(SecuritySideKey key) {
|
||||
return new TaskSecurityEyeData();
|
||||
}
|
||||
|
||||
|
||||
public TaskSecurityQuoterData get_quoter_data(uint key, Side side) { return get_quoter_data(new SecuritySideKey(key, side)); }
|
||||
public TaskSecurityQuoterData get_quoter_data(SecuritySideKey key) {
|
||||
return new TaskSecurityQuoterData();
|
||||
}
|
||||
|
||||
public TaskLiveData get_security_task(SecuritySideKey key, TaskType task_type) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,6 +123,15 @@ namespace BCG {
|
||||
|
||||
#endregion
|
||||
|
||||
#region Orders
|
||||
[System.ComponentModel.Category("Orders / Algo")]
|
||||
[System.ComponentModel.DisplayName("Default Account")]
|
||||
public string Account { get; set; }
|
||||
[System.ComponentModel.Category("Orders / Algo")]
|
||||
[System.ComponentModel.DisplayName("Default Qty")]
|
||||
public Nullable<double> DefaultQty { get; set; }
|
||||
#endregion
|
||||
|
||||
public NMSheetSettingLayout() {
|
||||
show_settings_header = false;
|
||||
show_exp_navigator = false;
|
||||
|
||||
@@ -18,6 +18,7 @@ using mbts.spark.filters;
|
||||
using System.Collections;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using bts.api.orderman;
|
||||
|
||||
namespace BCG {
|
||||
public partial class NMSheetControl : UserControl {
|
||||
@@ -555,6 +556,17 @@ namespace BCG {
|
||||
}
|
||||
private void _launch_order_entry_window(NMSheetTheoGrid.GridCell cell,
|
||||
OrderEntryWindow window_type) {
|
||||
Func<string, bts.AccountTuple> get_account = (string default_acc) => {
|
||||
string account = _settings.setting_layout.Account;
|
||||
if (String.IsNullOrEmpty(account)) {
|
||||
account = default_acc;
|
||||
}
|
||||
Nullable<uint> id = _get_account_id(account);
|
||||
if (!id.HasValue) {
|
||||
id = 0;
|
||||
}
|
||||
return new bts.AccountTuple(id.Value, account);
|
||||
};
|
||||
uint key;
|
||||
var found = _sheet_data.get_security_key(cell.expiration,
|
||||
cell.strike, cell.call_selected, out key);
|
||||
@@ -566,7 +578,20 @@ namespace BCG {
|
||||
if (sc_data.sec_md_map.TryGetValue(key, out var smd)) {
|
||||
switch (window_type) {
|
||||
case OrderEntryWindow.Ticket:
|
||||
_threaded_bb.post(SparkTags.ShowOrderTicketFromSecurityTag, smd);
|
||||
bool is_bid = NMSheetSettingColumnOrganization.get_column_info(cell.col).is_bid;
|
||||
bts.AccountTuple acc_tup = get_account("SMALL");
|
||||
Nullable<double> qty = _settings.setting_layout.DefaultQty;
|
||||
OrderDefinition od = new OrderDefinition() {
|
||||
SecurityKey = smd.id,
|
||||
TimeInForce = TimeInForce.Gtc,
|
||||
Account = acc_tup.name,
|
||||
AccountId = acc_tup.id
|
||||
};
|
||||
BBOPacket bbo = _sheet_data.get_bbo(smd.id);
|
||||
Tuple<double, UInt32> pr_sz = BBOPacket.get_md(bbo, is_bid);
|
||||
UInt32 effective_qty = qty.HasValue ? Convert.ToUInt32(Math.Abs(qty.Value)) : pr_sz.Item2;
|
||||
_threaded_bb.post(SparkTags.ShowOrderTicketTag,
|
||||
(new OrderDefinitionImmutable(od), pr_sz.Item1, effective_qty));
|
||||
break;
|
||||
case OrderEntryWindow.Ladder:
|
||||
_threaded_bb.post(SparkTags.ShowLadderTag, smd);
|
||||
|
||||
@@ -87,21 +87,21 @@ namespace BCG {
|
||||
}
|
||||
|
||||
private void _refresh_task_data(uint seckey) {
|
||||
string eye_task_text = String.Empty, quoter_task_text = String.Empty;
|
||||
bool dummy, is_bid, is_ask;
|
||||
NMSheetSettingColumnOrganization.parse_column(_last_mousemove_cell.col, out dummy, out dummy, out is_bid, out is_ask);
|
||||
if (is_bid ^ is_ask) {
|
||||
TaskingConsolidatedData task_data = _sheet_data.get_task_data();
|
||||
mbts.tasks.TaskLiveData eye_task_ld = task_data != null ? task_data.get_security_task(new mbts.engine.SecuritySideKey(seckey, is_bid ? Side.Buy : Side.Sell), mbts.tasks.TaskType.Eye) : null;
|
||||
if (eye_task_ld != null)
|
||||
eye_task_text = String.Format("Eye '{0}' {1} {2}", eye_task_ld.name, eye_task_ld.switch_state.ToString().ToUpper(),
|
||||
eye_task_ld.abs_accumulation.ToString("0") + "/" + eye_task_ld.task.common.exit_condition_parameter.ToString("0"));
|
||||
mbts.tasks.TaskLiveData quoter_task_ld = task_data != null ? task_data.get_security_task(new mbts.engine.SecuritySideKey(seckey, is_bid ? Side.Buy : Side.Sell), mbts.tasks.TaskType.Quoter) : null;
|
||||
if (quoter_task_ld != null)
|
||||
quoter_task_text += String.Format("Quoter '{0}' {1} {2}", quoter_task_ld.name, quoter_task_ld.switch_state.ToString().ToUpper(),
|
||||
quoter_task_ld.abs_accumulation.ToString("0") + "/" + quoter_task_ld.task.common.exit_condition_parameter.ToString("0"));
|
||||
}
|
||||
_set_text_visibility(_statusbar_toolstripstatus_task, true, String.Format("{0}{1}{2}", eye_task_text, String.IsNullOrEmpty(eye_task_text) ? String.Empty : " ", quoter_task_text));
|
||||
// string eye_task_text = String.Empty, quoter_task_text = String.Empty;
|
||||
// bool dummy, is_bid, is_ask;
|
||||
// NMSheetSettingColumnOrganization.parse_column(_last_mousemove_cell.col, out dummy, out dummy, out is_bid, out is_ask);
|
||||
// if (is_bid ^ is_ask) {
|
||||
// TaskingConsolidatedData task_data = _sheet_data.get_task_data();
|
||||
// mbts.tasks.TaskLiveData eye_task_ld = task_data != null ? task_data.get_security_task(new mbts.engine.SecuritySideKey(seckey, is_bid ? Side.Buy : Side.Sell), mbts.tasks.TaskType.Eye) : null;
|
||||
// if (eye_task_ld != null)
|
||||
// eye_task_text = String.Format("Eye '{0}' {1} {2}", eye_task_ld.name, eye_task_ld.switch_state.ToString().ToUpper(),
|
||||
// eye_task_ld.abs_accumulation.ToString("0") + "/" + eye_task_ld.task.common.exit_condition_parameter.ToString("0"));
|
||||
// mbts.tasks.TaskLiveData quoter_task_ld = task_data != null ? task_data.get_security_task(new mbts.engine.SecuritySideKey(seckey, is_bid ? Side.Buy : Side.Sell), mbts.tasks.TaskType.Quoter) : null;
|
||||
// if (quoter_task_ld != null)
|
||||
// quoter_task_text += String.Format("Quoter '{0}' {1} {2}", quoter_task_ld.name, quoter_task_ld.switch_state.ToString().ToUpper(),
|
||||
// quoter_task_ld.abs_accumulation.ToString("0") + "/" + quoter_task_ld.task.common.exit_condition_parameter.ToString("0"));
|
||||
// }
|
||||
// _set_text_visibility(_statusbar_toolstripstatus_task, true, String.Format("{0}{1}{2}", eye_task_text, String.IsNullOrEmpty(eye_task_text) ? String.Empty : " ", quoter_task_text));
|
||||
}
|
||||
|
||||
private static void _set_text_visibility(System.Windows.Forms.ToolStripStatusLabel l, bool new_visibility, string new_text) {
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
using mbts;
|
||||
using mbts.tasks;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BCG {
|
||||
partial class NMSheetControl {
|
||||
//private bool _task_quoter_enabled = true;
|
||||
|
||||
private void _init_task_quoter_ui() {
|
||||
// _task_quoter_enabled = true;
|
||||
// if (_task_quoter_enabled)
|
||||
// _disable_task_quoter_submenus();
|
||||
// else
|
||||
// _toolstripmenuitem_task_quoter.Enabled = false;
|
||||
// _toolstripmenuitem_settings_show_task_quoter_data.Click += (s, e) => _get_toolstripmenuitem_display_state_and_publish(_toolstripmenuitem_settings_show_task_quoter_data,
|
||||
// NMSheetSettingColumnOrganization.get_cols_for_type(NMSheetColumnType.Quoter).ToArray());
|
||||
}
|
||||
|
||||
private void _disable_task_quoter_submenus() {
|
||||
// _toolstripmenuitem_task_quoter.Enabled = _toolstripmenuitem_task_quoter_add_buys_to_task.Enabled =
|
||||
// _toolstripmenuitem_task_quoter_add_sells_to_task.Enabled = _toolstripmenuitem_task_quoter_add_buys_and_sells_to_task.Enabled = false;
|
||||
// _toolstripmenuitem_task_quoter_add_buys_to_task.DropDownItems.Clear();
|
||||
// _toolstripmenuitem_task_quoter_add_sells_to_task.DropDownItems.Clear();
|
||||
// _toolstripmenuitem_task_quoter_add_buys_and_sells_to_task.DropDownItems.Clear();
|
||||
|
||||
// List<ToolStripItem> create_menu_items = new List<ToolStripItem>();
|
||||
// foreach (ToolStripItem ti in _toolstripmenuitem_task_quoter.DropDownItems)
|
||||
// if (_create_menu_tag.Equals(ti.Tag))
|
||||
// create_menu_items.Add(ti);
|
||||
// create_menu_items.ForEach(ti => _toolstripmenuitem_task_quoter.DropDownItems.Remove(ti));
|
||||
}
|
||||
|
||||
private void _adapt_contextmenu_for_tasks_quoter() {
|
||||
// if (_task_quoter_enabled) {
|
||||
// _disable_task_quoter_submenus();
|
||||
// if (_task_selection.is_active) {
|
||||
// _toolstripmenuitem_task_quoter.Enabled = true;
|
||||
// ///Create
|
||||
// IEnumerable<TaskCommon> templates = _threaded_bb.sec_thread_retrieve_from_cache(TaskingTags.TemplatesTag) as IEnumerable<TaskCommon>;
|
||||
// templates = templates == null || templates.Count() == 0 ? new TaskCommon[] { TaskCommon.Default.with(name: "New Task") } : templates;
|
||||
// double min_strike = _task_selection.strikes.Min(), max_strike = _task_selection.strikes.Max();
|
||||
// string name = TaskType.Quoter.ToString() + " " +
|
||||
// _task_selection.exp.get_display_text() + " " +
|
||||
// (min_strike == max_strike ? min_strike.ToString("0.00") : String.Format("{0} - {1}", min_strike.ToString("0.00"), max_strike.ToString("0.00")));
|
||||
// int add_task_index = 0;
|
||||
// foreach (TaskCommon t in templates) {
|
||||
// ToolStripMenuItem add_task_item = new ToolStripMenuItem(t.name, null, (s, e) => {
|
||||
// mbts.tasks.TaskCommon common_task = t.with(task_type: TaskType.Quoter, name: name, side: TaskSide.None, id: Guid.NewGuid().ToString());
|
||||
// ExplicitTask explicit_task = ExplicitTask.Default.with(securities: _task_selection.keys, security_descriptions: _task_selection.names);
|
||||
// _threaded_bb.sec_thread_write(TaskingTags.ShowCreateTask, new ElectronicTradingTask(common_task, explicit_task));
|
||||
// });
|
||||
// add_task_item.Tag = _create_menu_tag;
|
||||
// add_task_item.Enabled = true;
|
||||
// _toolstripmenuitem_task_quoter.DropDownItems.Insert(add_task_index++, add_task_item);
|
||||
// }
|
||||
// //Add Buys to
|
||||
// TaskingConsolidatedData task_data = _sheet_data.get_task_data();
|
||||
// _toolstripmenuitem_task_quoter_add_buys_to_task.Enabled = true;
|
||||
// IEnumerable<TaskLiveData> tasks = task_data.get_tasks(TaskType.Quoter).OrderBy(t => t.name);
|
||||
// foreach (TaskLiveData t in tasks) {
|
||||
// ElectronicTradingTask mod_task = _get_mod_task(t.task, _task_selection);
|
||||
// ToolStripMenuItem add_item = new ToolStripMenuItem(t.get_summary_text(), null, (s, e) => _threaded_bb.sec_thread_write(TaskingTags.ShowEditTask, mod_task));
|
||||
// add_item.Enabled = t.task.common.side != TaskSide.Sell;
|
||||
// _toolstripmenuitem_task_quoter_add_buys_to_task.DropDownItems.Add(add_item);
|
||||
// }
|
||||
// /// Add Sells to
|
||||
// _toolstripmenuitem_task_quoter_add_sells_to_task.Enabled = true;
|
||||
// foreach (TaskLiveData t in tasks) {
|
||||
// ElectronicTradingTask mod_task = _get_mod_task(t.task, _task_selection);
|
||||
// ToolStripMenuItem add_item = new ToolStripMenuItem(t.get_summary_text(), null, (s, e) => _threaded_bb.sec_thread_write(TaskingTags.ShowEditTask, mod_task));
|
||||
// add_item.Enabled = t.task.common.side != TaskSide.Buy;
|
||||
// _toolstripmenuitem_task_quoter_add_sells_to_task.DropDownItems.Add(add_item);
|
||||
// }
|
||||
// /// Add Buys/Sells to
|
||||
// _toolstripmenuitem_task_quoter_add_buys_and_sells_to_task.Enabled = true;
|
||||
// foreach (TaskLiveData t in tasks) {
|
||||
// ElectronicTradingTask mod_task = _get_mod_task(t.task, _task_selection);
|
||||
// ToolStripMenuItem add_item = new ToolStripMenuItem(t.get_summary_text(), null, (s, e) => _threaded_bb.sec_thread_write(TaskingTags.ShowEditTask, mod_task));
|
||||
// add_item.Enabled = t.task.common.side == (TaskSide.Buy | TaskSide.Sell);
|
||||
// _toolstripmenuitem_task_quoter_add_buys_and_sells_to_task.DropDownItems.Add(add_item);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// private ElectronicTradingTask _get_task_quoter_mod_task(ElectronicTradingTask task) {
|
||||
// List<uint> secs = new List<uint>(task.explicit_task.securities);
|
||||
// List<string> secs_desc = new List<string>(task.explicit_task.security_descriptions);
|
||||
// secs.AddRange(_task_selection.keys);
|
||||
// secs_desc.AddRange(_task_selection.names);
|
||||
// ElectronicTradingTask mod_task = task.with(explicit_task: task.explicit_task.with(securities: secs, security_descriptions: secs_desc));
|
||||
// return mod_task;
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -83,26 +83,25 @@ namespace BCG {
|
||||
}
|
||||
|
||||
private bool _get_ee_switch_override(NMSheetSettings settings, MyAlertHelperData helper_data, int exp_index, int strike_index, ref Color out_color) {
|
||||
if (helper_data.is_ee_set_edge_or_size || helper_data.is_ee_price) {
|
||||
NMSheetRowAuxiliaryData aux_data = _formatted_theos.get_aux_data(exp_index, strike_index);
|
||||
if (aux_data != null) {
|
||||
NMSheetCallPutBidAskWrapper<NMSheetTaskEyeData> eye_data = aux_data.task_ee_data;
|
||||
if (eye_data != null) {
|
||||
NMSheetTaskEyeData secside_eye_data = eye_data.get_data(helper_data.is_call, helper_data.is_bid);
|
||||
if (secside_eye_data != null && secside_eye_data.eye_data != null) {
|
||||
if (helper_data.is_ee_price) {
|
||||
if (secside_eye_data.is_eye_cross) {
|
||||
out_color = _settings.setting_alerts.ee_fire_color.Value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (secside_eye_data.eye_data.is_on) {
|
||||
out_color = _settings.setting_alerts.ee_on_color.Value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!helper_data.is_theo)
|
||||
return false;
|
||||
NMSheetRowAuxiliaryData aux_data = _formatted_theos.get_aux_data(exp_index, strike_index);
|
||||
if (aux_data == null)
|
||||
return false;
|
||||
NMSheetCallPutBidAskWrapper<NMSheetTaskEyeData> t_data = aux_data.task_ee_data;
|
||||
if (t_data == null)
|
||||
return false;
|
||||
NMSheetTaskEyeData bid_sec_t_data =
|
||||
t_data.get_data(helper_data.is_call ? bts.api.PutOrCall.Call : bts.api.PutOrCall.Put,
|
||||
bts.api.Side.Buy);
|
||||
NMSheetTaskEyeData ask_sec_t_data =
|
||||
t_data.get_data(helper_data.is_call ? bts.api.PutOrCall.Call : bts.api.PutOrCall.Put,
|
||||
bts.api.Side.Sell);
|
||||
if ((bid_sec_t_data != null && bid_sec_t_data.is_on) ||
|
||||
(ask_sec_t_data != null && ask_sec_t_data.is_on)) {
|
||||
out_color = settings.setting_alerts.ee_on_color.HasValue ?
|
||||
settings.setting_alerts.ee_on_color.Value : Color.DarkGreen;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ using System.Reactive.Linq;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace mbts.spark {
|
||||
using RegionalTickFactors = user.settings.RegionalTickFactors;
|
||||
|
||||
class InlineOrderTicketProperties {
|
||||
public readonly InlineUserProperty<double> price;
|
||||
public readonly InlineUserProperty<double> size;
|
||||
@@ -102,6 +104,7 @@ namespace mbts.spark {
|
||||
|
||||
public SecurityImmutable security => _security.Value;
|
||||
public double price { get; set; }
|
||||
public RegionalTickFactors price_tick => security.regional_ticks();
|
||||
public CalculatorLogic<double> size_calculator { get; }
|
||||
public double display_quantity_divisor {
|
||||
get => _display_quantity_divisor;
|
||||
|
||||
@@ -225,10 +225,7 @@ namespace bts.spark {
|
||||
var security = try_get_security(order.Def.SecurityKey);
|
||||
var change_descs = new List<string>(1);
|
||||
|
||||
TickDisplaySettingsImmutable? price_display =
|
||||
security.HasValue && security.Value.HasContractSpec ?
|
||||
security.Value.ContractSpec.tick_factors().to_api_tick_display_settingsi() : null;
|
||||
|
||||
var price_display = TickUtils.get_tick(security, price).to_api_tick_display_settingsi();
|
||||
var price_qty_change_desc = OrderUtils.update_description(
|
||||
order, price, size, price_display);
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
<usp:PriceEntryControl
|
||||
Grid.ColumnSpan="2"
|
||||
usp:OrderModificationControl.IsDirty="{Binding price_dirty, FallbackValue={x:Null}}"
|
||||
ContractSpec="{Binding security.ContractSpec}"
|
||||
RegionalTick="{Binding price_tick}"
|
||||
Focusable="false"
|
||||
TickDefaultValue="{Binding current_price, Converter={StaticResource TickDefaultPriceConverter}, FallbackValue={u:Double 0}}"
|
||||
Value="{Binding price}"
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace mbts.spark {
|
||||
get {
|
||||
var m = new OrderMetadata { KeyBinding = string.Empty, NoProps = false };
|
||||
if (_studio_meta.HasValue && _studio_meta.Value.badge_color.HasValue)
|
||||
m.Color = _studio_meta.Value.badge_color.Value.rgb_color();
|
||||
m.Color = _studio_meta.Value.badge_color.Value.to_uint();
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) =>
|
||||
@@ -366,6 +372,8 @@ namespace mbts.spark {
|
||||
public class Nothing { Nothing() { } }
|
||||
|
||||
public class TC2Tags {
|
||||
public static ITag<NMSheetAllTaskingData> TaskData { get; } =
|
||||
_mk_tag<NMSheetAllTaskingData>();
|
||||
// Data request for a sheet
|
||||
// Published by NMSheetDriverControlStrip
|
||||
public static ITag<NMSheetDataRequest> NMSheetDataRequestTag(string id) =>
|
||||
|
||||
Loaded 100 of 215 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user