Files
spark/src/client/spark/Modules/Analytics/AnalyticsShellModule.cs
T
John Colvin b499a5c38b refactor: Move IDisposable utils to Spark.Core.Disposables ns
* Move Anonymous/FinalizableDisposable to own file
* Rename DisposableCombo -> ImmutableDisposable and move it to its own file
* Clean up IDisposable utils impl, but keep changes to calling code minimial
2022-08-22 00:05:04 -04:00

256 lines
10 KiB
C#

namespace mbts.spark {
using bts;
using bts.api;
using bts.api.analytics;
using bts.api.core;
using bts.collections;
using bts.shell;
using bts.shell.pnl;
using bts.spark;
using mbts.analytics;
using mbts.persist;
using mbts.ui;
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.Core.Data;
using Spark.Core.Disposables;
using Spark.Core.Reactive;
using Spark.Trading;
using Spark.ViewModel;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
[Export(typeof(IShellModule))]
class AnalyticsShellModule : IShellModule, IShellModuleViewFactory {
readonly IBus _bus;
readonly IWindowManager _wm;
readonly List<IShellWindowFactory> _window_factories;
IDisposable _dispose;
[ImportingConstructor]
public AnalyticsShellModule(
IBus bus,
WindowManager wm,
UserSettingsHub settings_hub,
OrdersModel orders_model,
IPositionModel position_model,
ISecurityMetadataStore sec_meta_store,
Lazy<UserTuple> user) {
_wm = wm;
_bus = bus;
var reports_demuxer = new TableUpdateDemuxer<ReportImmutable?, int>(default, false);
var nullable_reports_src = bus.subscribe(SparkTags.ReportBlackboardTags.ListTag)
.Table(r => r.Id)
.Select(
r => new ReportImmutable?(r),
r => r?.Id ?? throw new ArgumentNullException(nameof(r)));
_window_factories = new() {
new VolSurfaceWindowFactory(this, bus),
new AnalyticsExpirationParametersWindowFactory(this, bus),
new SlideReportWindowFactory(this, bus, reports_demuxer.subscribe),
new ComboReportWindowFactory(this, bus, reports_demuxer.subscribe),
new PNLWindowFactory(
this, bus, settings_hub, orders_model, position_model, sec_meta_store),
new DayFillsWindowFactory(
this, bus, settings_hub, position_model, sec_meta_store, user.Value)
};
var vol_surfaces_src = _bus.subscribe(SparkTags.VolSurfaceListTag).OnDispatcher();
var reports_src = _bus.subscribe(SparkTags.ReportBlackboardTags.ListTag).OnDispatcher();
_dispose = Disposable.Create(
vol_surfaces_src.Subscribe(_on_vol_surfaces),
reports_src.Subscribe(_on_reports),
nullable_reports_src.Subscribe(reports_demuxer),
reports_demuxer,
vm.launch_exp_params_view_cmd.subscribe_executed(_launch_exp_params_view),
vm.launch_pnl_cmd.subscribe_executed(_launch_pnl),
vm.launch_day_fills_cmd.subscribe_executed(_launch_day_fills),
// vol surface
vm.vol_surface_launcher_vm.launch_cmd.subscribe_executed(_launch_vol_surface),
vm.vol_surface_launcher_vm.create_cmd.subscribe_executed(_create_vol_surface),
vm.vol_surface_launcher_vm.delete_cmd.subscribe_executed(_delete_vol_surface),
// slide
vm.slide_report_launcher_vm.launch_cmd.subscribe_executed(_launch_slide_report),
vm.slide_report_launcher_vm.create_cmd.subscribe_executed(_create_slide_report),
vm.slide_report_launcher_vm.delete_cmd.subscribe_executed(_delete_slide_report),
// combo
vm.combo_report_launcher_vm.launch_cmd.subscribe_executed(_launch_combo_report),
vm.combo_report_launcher_vm.create_cmd.subscribe_executed(_create_combo_report),
vm.combo_report_launcher_vm.delete_cmd.subscribe_executed(_delete_combo_report));
}
public enum WindowType { Main, Heatmap }
public string name => "Analytics";
public ImageSource icon => Icons.analytics;
public int priority => 20;
public IEnumerable<SparkCommand> actions => Enumerable.Empty<SparkCommand>();
public AnalyticsShellModuleVM vm { get; } = new();
public Task<IShellWindow> create(Stream load_stream) =>
ShellWindowFactory.create(load_stream, _window_factories);
public UIElement create_view() =>
new AnalyticsShellModuleView { DataContext = vm };
public void Dispose() =>
Disposable.dispose(ref _dispose);
void _create_vol_surface(string _) {
var settings = VolSurfaceSettings.Default(string.Empty);
var vm = new VolSurfaceSettingsEditorVM(
_bus, settings, v => _bus.post(SparkTags.VolSurfaceCreateTag, v)) {
can_edit_name = true
};
var window = new VolSurfaceSettingsEditor {
DataContext = vm,
WindowStartupLocation = WindowStartupLocation.CenterScreen
};
window.Show();
select_section_delayed("configuration");
async void select_section_delayed(string section) {
await Task.Delay(100);
vm.selected_section = section;
}
}
void _launch_exp_params_view() {
var settings = AnalyticsExpirationParametersSettings.Default;
_bus.post(SparkTags.show_analytics_exp_params, settings);
}
void _launch_pnl() =>
_bus.post(SparkTags.ShowPNLTag, null);
void _launch_day_fills() =>
_bus.post(SparkTags.show_day_fills, DayFillsSettings.Default());
void _launch_vol_surface(int id) {
var windows = _wm.list_windows();
if (windows.OfType<VolSurfaceWindow>().TryGetFirst(w => w.vs_id == id, out var win)) {
_wm.MakeVisible(win);
return;
}
_bus.post(SparkTags.ShowVolSurface, new() { id = id });
}
void _delete_vol_surface(int id) {
if (BTSMessageBox.Confirm($"Are you sure you want to delete {name}?", "Vol Surface")) {
_bus.post(SparkTags.VolSurfaceDeleteTag, id);
}
}
void _on_vol_surfaces(IDictionary<int, string> id_names) {
vm.vol_surface_launcher_vm.items.sync_with(id_names.Select(
kv => new KeyValueItemVM<int, string>(kv.Key, kv.Value)));
// reset titles for all open vol surface windows
foreach (var window in _wm.list_windows().OfType<VolSurfaceWindow>()) {
window.Title = id_names.GetValueOrDefault(window.vs_id) ?? "(...)";
}
}
void _create_slide_report(string _) {
var vm = new SlideReportSettingsVM(
SlideReportSettings.Default(),
new(new Report { ReportType = Report.Types.ReportType.Slide }),
_bus.subscribe(SparkTags.VolSurfaceListTag),
_bus.subscribe(SparkTags.AccountsTag),
_bus.subscribe(SparkTags.SecuritiesTag));
vm.selected_section = vm.configuration_vm;
var win = new SlideReportCreationDialog() {
DataContext = vm
};
WindowUtilities.connect_vm(win, vm);
vm.ok_cmd.executed += commit;
win.move_to_mouse(-100, -200);
win.Show();
async void commit((GreekDisplay[] greeks, PriceDisplayFactors price_disp, ReportImmutable rep) tup) {
WindowUtilities.force_close(win);
_bus.post(SparkTags.ReportBlackboardTags.Create, tup.rep);
var persisted_rep = await _bus.subscribe(SparkTags.ReportBlackboardTags.ListTag)
.Select(reps => reps.Values.TryGetFirst(
r => r.ReportName == tup.rep.ReportName, out var prep) ? prep : (ReportImmutable?)null)
.Where(r => r.HasValue)
.FirstOrDefaultAsync();
if (!persisted_rep.HasValue) {
return;
}
var settings = SlideReportSettings.Default(persisted_rep.Value.Id);
settings.greeks = tup.greeks;
settings.price = tup.price_disp;
vm.grid_vm.assign_to(settings);
_bus.post(SparkTags.ShowSlideReportTag, settings);
}
}
void _delete_slide_report(int id) =>
_bus.post(SparkTags.ReportBlackboardTags.Delete, id);
void _launch_slide_report(int id) =>
_bus.post(SparkTags.ShowSlideReportTag, SlideReportSettings.Default(id));
void _create_combo_report(string _) {
var vm = new ComboReportSettingsVM(
_bus.subscribe(SparkTags.AccountsTag), _bus.subscribe(SparkTags.SecuritiesTag));
vm.load_from(new(new Report { ReportType = Report.Types.ReportType.Slide }));
var win = new ComboReportCreationDialog() {
DataContext = vm
};
WindowUtilities.connect_vm(win, vm);
vm.commit_cmd.executed += commit;
win.move_to_mouse(-100, -100);
win.Show();
async void commit(ReportImmutable rep) {
WindowUtilities.force_close(win);
_bus.post(SparkTags.ReportBlackboardTags.Create, rep);
var persisted_rep = await _bus.subscribe(SparkTags.ReportBlackboardTags.ListTag)
.Select(reps => reps.Values.TryGetFirst(
r => r.ReportName == rep.ReportName, out var prep) ? prep : (ReportImmutable?)null)
.Where(r => r.HasValue)
.FirstOrDefaultAsync();
if (!persisted_rep.HasValue) {
return;
}
var settings = ComboReportSettings.Default(persisted_rep.Value.Id);
_bus.post(SparkTags.ShowComboReportTag, settings);
}
}
void _delete_combo_report(int id) =>
_bus.post(SparkTags.ReportBlackboardTags.Delete, id);
void _launch_combo_report(int id) =>
_bus.post(SparkTags.ShowComboReportTag, ComboReportSettings.Default(id));
void _on_reports(IReadOnlyDictionary<int, ReportImmutable> reports) {
vm.slide_report_launcher_vm.items.Clear();
vm.combo_report_launcher_vm.items.Clear();
foreach (var rep in reports.Values) {
switch (rep.ReportType) {
case Report.Types.ReportType.Slide:
vm.slide_report_launcher_vm.items.Add(new(rep.Id, rep.ReportName));
break;
case Report.Types.ReportType.Combo:
vm.combo_report_launcher_vm.items.Add(new(rep.Id, rep.ReportName));
break;
}
}
}
}
}