Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b320a1075 | ||
|
|
e838413541 | ||
|
|
7d6d72b423 | ||
|
|
891d674ca4 | ||
|
|
92c1508b8c | ||
|
|
466915f6e9 | ||
|
|
1c68cfa08e | ||
|
|
cc75872c04 | ||
|
|
7e93866596 | ||
|
|
f4213eefe9 | ||
|
|
72bfafb376 | ||
|
|
5dbacfddd5 | ||
|
|
e29ea5d89b | ||
|
|
2885d929a8 | ||
|
|
a3e5bc4fba | ||
|
|
bb19f737d5 |
No files matched your search
@@ -24,3 +24,4 @@ project.lock.json
|
||||
src/server/sparkd/orderman/perf_analysis/data
|
||||
src/server/sparkd/orderman/perf_analysis/logs/
|
||||
src/server/sparkd/orderman/perf_analysis/trace_data/
|
||||
src/lib/orderman/perf_analysis/logs/latency_data/
|
||||
@@ -54,6 +54,8 @@ else ()
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/web ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/data_files ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/src/lib/libspark.so ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND mkdir ARGS -p ${CMAKE_BINARY_DIR}/server/plugins
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/sdk/examples/order_plugin_example.so ${CMAKE_BINARY_DIR}/server/plugins/
|
||||
COMMENT "Creating server runtime layout"
|
||||
DEPENDS sparkd data_files_dir)
|
||||
|
||||
|
||||
@@ -5,11 +5,9 @@ using mbts.collections;
|
||||
using mbts.spark.utilities;
|
||||
using mbts.ui;
|
||||
using mbts.ui.controls;
|
||||
using mbts.ui.settings;
|
||||
using mbts.ui.spark;
|
||||
using mbts.ui.utility;
|
||||
using mbts.utils;
|
||||
using bts.utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
@@ -18,7 +16,6 @@ using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Windows.Input;
|
||||
|
||||
|
||||
namespace mbts.spark {
|
||||
partial class MarketViewVM {
|
||||
public class Row : SecurityMDRow, IDisposable, IEquatable<Row>, DIYGrid.IRowVM, DIYGrid.IActionableRowVM {
|
||||
@@ -78,16 +75,29 @@ namespace mbts.spark {
|
||||
ask_price_click = new DelegateCommand(() => _show_order_ticket(MarketViewView.Columns.Ask));
|
||||
ask_size_click = new DelegateCommand(() => _show_order_ticket(MarketViewView.Columns.AskSize));
|
||||
working_asks_click = new DelegateCommand(() => _show_order_book(MarketViewView.Columns.WorkingAsks));
|
||||
|
||||
_position.value_set += position_value_set;
|
||||
_inside_bids.value_set += inside_bids_value_set;
|
||||
_inside_asks.value_set += inside_asks_value_set;
|
||||
_day_change.Changed += day_change_Changed;
|
||||
_animation.AnimationsChanged += on_animations_changed;
|
||||
void on_animations_changed() => RaisePropertyChanged(nameof(animations));
|
||||
|
||||
_dispose = Disposable.Create(
|
||||
_orders_model.on_security_root_orders(security.Id).OnDispatcher().Subscribe(_on_orders),
|
||||
_position.OnDispatcher().Subscribe(v => _animation.animate_position(v.newval > v.oldval)),
|
||||
_inside_bids.OnDispatcher().Subscribe(v => _animation.animate_working_bids_inside(v.newval)),
|
||||
_inside_asks.OnDispatcher().Subscribe(v => _animation.animate_working_asks_inside(v.newval)),
|
||||
_day_change.OnDispatcher().Subscribe(v => _animation.animate_day_change(v.newval > v.oldval)),
|
||||
Disposable.Create(() => _animation.AnimationsChanged -= on_animations_changed)
|
||||
Disposable.Create(() => {
|
||||
_position.value_set -= position_value_set;
|
||||
_inside_bids.value_set -= inside_bids_value_set;
|
||||
_inside_asks.value_set -= inside_asks_value_set;
|
||||
_day_change.Changed -= day_change_Changed;
|
||||
_animation.AnimationsChanged -= on_animations_changed;
|
||||
})
|
||||
);
|
||||
|
||||
void position_value_set((int oldval, int newval) v) => _animation.animate_position(v.newval > v.oldval);
|
||||
void inside_bids_value_set((bool oldval, bool newval) v) => _animation.animate_working_bids_inside(v.newval);
|
||||
void inside_asks_value_set((bool oldval, bool newval) v) => _animation.animate_working_asks_inside(v.newval);
|
||||
void day_change_Changed(double oldval, double newval) => _animation.animate_day_change(newval > oldval);
|
||||
void on_animations_changed() => RaisePropertyChanged(nameof(animations));
|
||||
}
|
||||
|
||||
public event Action invalidated;
|
||||
@@ -129,27 +139,52 @@ namespace mbts.spark {
|
||||
|
||||
public void raise_invalidated() => invalidated?.Invoke();
|
||||
|
||||
public void refresh() {
|
||||
/// <summary>
|
||||
/// Returns a list of IDisposable 'update jobs.' Each item represents a job that will be executed when disposed; all jobs should be executed on the dispatcher thread.
|
||||
/// </summary>
|
||||
// Note: not guarenteed to be on the dispatcher thread, so all view-notifying actions should be wrapped in a IDisposable.
|
||||
// Having said that, perform as much work as possible locally.
|
||||
public List<IDisposable> refresh() {
|
||||
var update_jobs = new List<IDisposable>();
|
||||
bool dirty = false;
|
||||
if (md.md.get_bbo(ref _bbo_ref, out NativePriceSize b, out NativePriceSize a)) {
|
||||
_bid_price.set(b.price);
|
||||
_bid_size.set(b.size);
|
||||
_ask_price.set(a.price);
|
||||
_ask_size.set(a.size);
|
||||
_inside_bids.on_next_distinct(_bid_price.Value >= _working_best_bid.value, ref dirty);
|
||||
_inside_asks.on_next_distinct(_ask_price.Value <= _working_best_ask.value, ref dirty);
|
||||
prop_job(_bid_price, b.price);
|
||||
prop_job(_bid_size, b.size);
|
||||
prop_job(_ask_price, a.price);
|
||||
prop_job(_ask_size, a.size);
|
||||
cell_prop_job(_inside_bids, b.price >= _working_best_bid.value);
|
||||
cell_prop_job(_inside_asks, a.price >= _working_best_ask.value);
|
||||
}
|
||||
if (md.md.get_last_trade(ref _last_ref, out NativePriceSize ps, out DateTime ts, out ulong v)) {
|
||||
_last_price.set(ps.price);
|
||||
_last_size.on_next_distinct(ps.size, ref dirty);
|
||||
_volume.on_next_distinct(v, ref dirty);
|
||||
double new_last_price = last_price;
|
||||
if (md.md.get_last_trade(ref _last_ref, out NativePriceSize ps, out ulong v)) {
|
||||
new_last_price = ps.price;
|
||||
prop_job(_last_price, new_last_price);
|
||||
cell_prop_job(_last_size, ps.size);
|
||||
cell_prop_job(_volume, v);
|
||||
}
|
||||
double new_settlement = md.md.settlement_price;
|
||||
prop_job(_settlement, new_settlement);
|
||||
prop_job(_session_low, md.md.session_low);
|
||||
prop_job(_session_high, md.md.session_high);
|
||||
prop_job(_day_change, new_last_price - new_settlement);
|
||||
|
||||
if (dirty) {
|
||||
update_jobs.Add(Disposable.Create(() => {
|
||||
invalidated?.Invoke();
|
||||
}));
|
||||
}
|
||||
return update_jobs;
|
||||
|
||||
void prop_job<T>(Property<T> p, T newval) {
|
||||
var uj = p.set_as_job(newval);
|
||||
if (uj != null)
|
||||
update_jobs.Add(uj);
|
||||
}
|
||||
void cell_prop_job<T>(CellProperty<T> p, T newval) {
|
||||
var uj = p.on_next_distinct_as_job(newval, ref dirty);
|
||||
if (uj != null)
|
||||
update_jobs.Add(uj);
|
||||
}
|
||||
_settlement.set(md.md.settlement_price);
|
||||
_session_low.set(md.md.session_low);
|
||||
_session_high.set(md.md.session_high);
|
||||
_day_change.set(last_price - settlement);
|
||||
if (dirty)
|
||||
invalidated?.Invoke();
|
||||
}
|
||||
|
||||
public bool Equals(Row other) =>
|
||||
|
||||
@@ -3,10 +3,13 @@ using mbts.spark.filters;
|
||||
using mbts.ui;
|
||||
using mbts.ui.utility;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using static bts.shell.MarketViewWindowFactory;
|
||||
@@ -14,7 +17,7 @@ using static mbts.ui.controls.DIYGrid;
|
||||
using static mbts.ui.spark.MarketViewView;
|
||||
|
||||
namespace mbts.spark {
|
||||
partial class MarketViewVM : SecurityMDGrid<MarketViewVM.Row, SecurityMD> {
|
||||
partial class MarketViewVM : SecurityMDGrid<MarketViewVM.Row, SecurityMD>, IPrepareUpdateForDispatcher {
|
||||
readonly IBus _bus;
|
||||
readonly OrdersModel _orders_model;
|
||||
|
||||
@@ -112,8 +115,7 @@ namespace mbts.spark {
|
||||
}), DataGridFilterHelper.hook_filters(rows_view,
|
||||
security_filter, bid_price_filter, bid_size_filter, ask_price_filter, ask_size_filter, last_price_filter, last_size_filter, day_change_filter, settlement_filter,
|
||||
session_low_filter, session_high_filter, position_filter, working_bid_volume_filter, working_ask_volume_filter, volume_filter, security_key_filter),
|
||||
securities_connectable.Connect(),
|
||||
WorkLoop.Start("MarketView", _refresh)
|
||||
securities_connectable.Connect()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -159,6 +161,25 @@ namespace mbts.spark {
|
||||
}
|
||||
#endregion
|
||||
|
||||
public IDisposable prepare_update() {
|
||||
ConcurrentBag<List<IDisposable>> to_update = new ConcurrentBag<List<IDisposable>>();
|
||||
try {
|
||||
Parallel.For(0, _row_vms.Count, i => {
|
||||
var r = _row_vms[i];
|
||||
var update_jobs = r.refresh();
|
||||
if (update_jobs.Count > 0)
|
||||
to_update.Add(update_jobs);
|
||||
});
|
||||
} catch (IndexOutOfRangeException) {
|
||||
// since rows (securities) will only be added/removed through rare user intervention,
|
||||
// it is worth catching the occassional exception in exchange for lock-free code.
|
||||
// if a row misses an update, or gets updated more than once, that's okay too;
|
||||
// in 100ms it will tick again, so the data should never be more than a few 100 ms old, and rarely older than 100.
|
||||
}
|
||||
// return null, rather than an empty IDisposable; this signals to the UpdateMaster that it may skip the call to Dispatcher.InvokeAsync() as there is nothing to dispose.
|
||||
return to_update.Count == 0 ? null : Disposable.Create(() => to_update.SelectMany(_ => _).DisposeAll());
|
||||
}
|
||||
|
||||
protected override Row row_factory(SecurityMD smd) => new Row(_bus, smd, _orders_model);
|
||||
protected override void on_row_removed(Row row) => row.Dispose();
|
||||
protected override IEnumerable<SortingCriteria> get_default_sorting() { yield return new SortingCriteria(nameof(Row.security), true); }
|
||||
@@ -167,4 +188,4 @@ namespace mbts.spark {
|
||||
foreach (var r in _row_vms) r.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,16 +14,18 @@ using System.Windows;
|
||||
namespace mbts.spark {
|
||||
class MarketViewWindow : SparkWindow<MarketViewWindowFactory.StartupData>, ISharedWindow {
|
||||
const string _window_type = "MarketView", _thread_id = "MarketView", _window_type_display_name = "Market View";
|
||||
readonly DispatcherUpdateMaster _dispatcher_update_master;
|
||||
readonly OrdersModel _orders_model;
|
||||
readonly AllowOnce _init_guard = new AllowOnce("MarketView");
|
||||
MarketViewVM _vm;
|
||||
MarketViewView _view;
|
||||
MarketViewWindowFactory.StartupData _state;
|
||||
IReadOnlyList<SparkCommand> _commands;
|
||||
IDisposable _subscriptions;
|
||||
IDisposable _resources;
|
||||
|
||||
public MarketViewWindow(MarketViewWindowFactory factory, IBus bus, OrdersModel orders_model, MarketViewWindowFactory.StartupData state)
|
||||
public MarketViewWindow(MarketViewWindowFactory factory, DispatcherUpdateMaster dispatcher_update_master, IBus bus, OrdersModel orders_model, MarketViewWindowFactory.StartupData state)
|
||||
: base("Market View", bus, factory, SparkCommands.ShowMarketView.icon) {
|
||||
_dispatcher_update_master = dispatcher_update_master;
|
||||
_orders_model = orders_model;
|
||||
_state = state;
|
||||
Icon.Freeze();
|
||||
@@ -57,12 +59,14 @@ namespace mbts.spark {
|
||||
SparkCommands.ShowSyntheticCreate.complete(_vm.selected_securities_observable(), secs => secs.Count > 0 && secs.Count <= 24, secs => new SecurityCriteria(secs)),
|
||||
SparkCommands.change_securities_command(() => (update_securities_cmd, _state.security_criteria))
|
||||
};
|
||||
_subscriptions = _bus.subscribe(update_securities_cmd.tag).OnDispatcher().Subscribe(c =>
|
||||
_state_changed?.Invoke(_state = new MarketViewWindowFactory.StartupData(c, _vm.rows_view.GetSortingCriteria(), _vm.get_filter_states())));
|
||||
_resources = Disposable.Create(
|
||||
_bus.subscribe(update_securities_cmd.tag).OnDispatcher().Subscribe(
|
||||
c => _state_changed?.Invoke(_state = new MarketViewWindowFactory.StartupData(c, _vm.rows_view.GetSortingCriteria(), _vm.get_filter_states()))),
|
||||
_dispatcher_update_master.attach(_vm));
|
||||
}
|
||||
|
||||
public override void Dispose() {
|
||||
Disposable.dispose(ref _subscriptions);
|
||||
Disposable.dispose(ref _resources);
|
||||
_vm.Dispose();
|
||||
Commands.OfType<IDisposable>().DisposeAll();
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace bts.shell {
|
||||
class MarketViewWindowFactory : ShellWindowFactory<MarketViewWindowFactory.StartupData> {
|
||||
readonly IBus _bus;
|
||||
readonly OrdersModel _orders_model;
|
||||
readonly DispatcherUpdateMaster _dispatcher_update_master = new DispatcherUpdateMaster("MarketView DispatcherUpdateMaster");
|
||||
|
||||
public MarketViewWindowFactory(MarketShellModule module, IBus bus, OrdersModel orders_model) : base(module, "MarketView") {
|
||||
_bus = bus;
|
||||
@@ -25,7 +26,7 @@ namespace bts.shell {
|
||||
void _show(SecurityCriteria criteria) =>
|
||||
_bus.post(SparkTags.ShowWindow, _create(new StartupData(criteria, new List<SortingCriteria> { new SortingCriteria(nameof(MarketViewVM.Row.security), true) }, null)));
|
||||
|
||||
IShellWindow _create(StartupData state) => new MarketViewWindow(this, _bus, _orders_model, state);
|
||||
IShellWindow _create(StartupData state) => new MarketViewWindow(this, _dispatcher_update_master, _bus, _orders_model, state);
|
||||
|
||||
[ProtoContract]
|
||||
public class StartupData {
|
||||
|
||||
@@ -20,23 +20,23 @@ namespace mbts.spark
|
||||
public static void add_dynamic_order_defs(List<CustomOrderDefinitionImmutable> defs,
|
||||
Func<CustomOrderDefinition.CustomOneofCase, CustomOrderDefinition> factory)
|
||||
{
|
||||
var dyntypes = _list.Value;
|
||||
foreach (var d in dyntypes.dynamic_orders)
|
||||
{
|
||||
var dorder = factory(CustomOrderDefinition.CustomOneofCase.Dynamic);
|
||||
dorder.Dynamic.DynamicOrderType = d.type_name;
|
||||
foreach (var p in d.parameter_keys)
|
||||
dorder.Dynamic.Parameters.Add(p, string.Empty);
|
||||
defs.Add(new CustomOrderDefinitionImmutable(dorder));
|
||||
}
|
||||
// var dyntypes = _list.Value;
|
||||
// foreach (var d in dyntypes.dynamic_orders)
|
||||
// {
|
||||
// var dorder = factory(CustomOrderDefinition.CustomOneofCase.Dynamic);
|
||||
// dorder.Dynamic.DynamicOrderType = d.type_name;
|
||||
// foreach (var p in d.parameter_keys)
|
||||
// dorder.Dynamic.Parameters.Add(p, string.Empty);
|
||||
// defs.Add(new CustomOrderDefinitionImmutable(dorder));
|
||||
// }
|
||||
}
|
||||
|
||||
internal static List<NameValueVM> get_parameters(string dyntype)
|
||||
{
|
||||
List<NameValueVM> par = new List<NameValueVM>();
|
||||
var order = _list.Value.dynamic_orders.FirstOrDefault(x => x.type_name == dyntype);
|
||||
if (order != null)
|
||||
par.AddRange(order.parameter_keys.Select(x => new NameValueVM() { name = x, value = string.Empty }));
|
||||
// var order = _list.Value.dynamic_orders.FirstOrDefault(x => x.type_name == dyntype);
|
||||
// if (order != null)
|
||||
// par.AddRange(order.parameter_keys.Select(x => new NameValueVM() { name = x, value = string.Empty }));
|
||||
return par;
|
||||
}
|
||||
}
|
||||
@@ -115,17 +115,17 @@ namespace mbts.spark
|
||||
|
||||
public override void assign_to(CustomOrderDefinition value)
|
||||
{
|
||||
if (_child_order == null)
|
||||
_select_child_order(model.factory.default_order_type(_security.Value, true));
|
||||
_validate();
|
||||
if (!HasErrors)
|
||||
{
|
||||
var i = factory.dynamic_order();
|
||||
i.DynamicOrderType = _dyn_type;
|
||||
set_parameter_dictionary(i.Parameters);
|
||||
child_order.assign_to(i.Child);
|
||||
value.Dynamic = i;
|
||||
}
|
||||
// if (_child_order == null)
|
||||
// _select_child_order(model.factory.default_order_type(_security.Value, true));
|
||||
// _validate();
|
||||
// if (!HasErrors)
|
||||
// {
|
||||
// var i = factory.dynamic_order();
|
||||
// i.DynamicOrderType = _dyn_type;
|
||||
// set_parameter_dictionary(i.Parameters);
|
||||
// child_order.assign_to(i.Child);
|
||||
// value.Dynamic = i;
|
||||
// }
|
||||
}
|
||||
|
||||
void set_parameter_dictionary(Google.Protobuf.Collections.MapField<string, string> par)
|
||||
@@ -208,4 +208,4 @@ namespace mbts.spark
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,7 +211,7 @@ namespace mbts.spark {
|
||||
_security_md.Value.md.get_bbo(ref _bbo_ref, out co2.NativePriceSize bid, out co2.NativePriceSize ask);
|
||||
_best_bid = bid.price;
|
||||
_best_ask = ask.price;
|
||||
_security_md.Value.md.get_last_trade(ref _last_trade_ref, out co2.NativePriceSize ps, out DateTime ts, out ulong v);
|
||||
_security_md.Value.md.get_last_trade(ref _last_trade_ref, out co2.NativePriceSize ps, out ulong v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
using bts;
|
||||
using bts.utils;
|
||||
using mbts.collections;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Concurrency;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace mbts.spark {
|
||||
interface IPrepareUpdateForDispatcher {
|
||||
IDisposable prepare_update();
|
||||
}
|
||||
|
||||
class DispatcherUpdateMaster : IDisposable {
|
||||
readonly string _name;
|
||||
readonly DispatcherPriority _invocation_priority;
|
||||
SetMap<Dispatcher, IPrepareUpdateForDispatcher> _vms;
|
||||
int _state = States.ReadyForUpdate;
|
||||
IDisposable _dispose;
|
||||
|
||||
public DispatcherUpdateMaster(string name)
|
||||
: this(name, WorkLoop.default_interval, WorkLoop.default_priority) { }
|
||||
|
||||
public DispatcherUpdateMaster(string name, TimeSpan period, DispatcherPriority invocation_priority) {
|
||||
_name = name;
|
||||
_vms = new SetMap<Dispatcher, IPrepareUpdateForDispatcher>(EqualityComparer.Create<Dispatcher, int>(d => d.Thread.ManagedThreadId));
|
||||
_dispose = ThreadPoolScheduler.Instance.SchedulePeriodic(period, _update_async);
|
||||
_invocation_priority = invocation_priority;
|
||||
}
|
||||
|
||||
public IDisposable attach(IPrepareUpdateForDispatcher vm, Dispatcher dispatcher) {
|
||||
var clone = _vms.clone();
|
||||
clone.add(dispatcher, vm);
|
||||
_vms = clone;
|
||||
return Disposable.Create(() => _detach(vm, dispatcher));
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
Thread.VolatileWrite(ref _state, States.Disposed);
|
||||
Disposable.dispose(ref _dispose);
|
||||
}
|
||||
|
||||
void _detach(IPrepareUpdateForDispatcher preper, Dispatcher dispatcher) {
|
||||
var clone = _vms.clone();
|
||||
clone.remove(dispatcher, preper);
|
||||
_vms = clone;
|
||||
}
|
||||
|
||||
async void _update_async() {
|
||||
if (Interlocked.CompareExchange(ref _state, States.UpdateInProgress, States.ReadyForUpdate) != States.ReadyForUpdate) {
|
||||
return;
|
||||
}
|
||||
var temp = _vms;
|
||||
try {
|
||||
ConcurrentBag<(Dispatcher dispatcher, ConcurrentBag<IDisposable> update)> update_jobs =
|
||||
new ConcurrentBag<(Dispatcher dispatcher, ConcurrentBag<IDisposable> update_jobs)>();
|
||||
await Task.Run(() => {
|
||||
Parallel.ForEach(temp, dispatcher_group => {
|
||||
ConcurrentBag<IDisposable> update = new ConcurrentBag<IDisposable>();
|
||||
Parallel.ForEach(dispatcher_group, vm => {
|
||||
// need to check for null, that indicates an empty update (rather than an actual empty enumerable)
|
||||
var ujs = vm.prepare_update();
|
||||
if (ujs != null)
|
||||
update.Add(ujs);
|
||||
});
|
||||
if (update.Count > 0)
|
||||
update_jobs.Add((dispatcher_group.Key, update));
|
||||
});
|
||||
});
|
||||
await Task.WhenAll(update_jobs.Select(_update_dispatcher_group_async));
|
||||
} catch (Exception ex) {
|
||||
Log.Ui.error($"{_name} error during parallel update: {ex}");
|
||||
} finally {
|
||||
// signal that the update is complete, and we are ready for another
|
||||
Interlocked.CompareExchange(ref _state, States.ReadyForUpdate, States.UpdateInProgress);
|
||||
}
|
||||
}
|
||||
|
||||
async Task _update_dispatcher_group_async((Dispatcher dispatcher, ConcurrentBag<IDisposable> update_jobs) t) =>
|
||||
await t.dispatcher.InvokeAsync(() => t.update_jobs.DisposeAll(), _invocation_priority);
|
||||
|
||||
static class States {
|
||||
public const int
|
||||
ReadyForUpdate = 0,
|
||||
UpdateInProgress = 1,
|
||||
Disposed = 2;
|
||||
}
|
||||
}
|
||||
|
||||
static class DispatcherUpdateMasterExtensions {
|
||||
public static IDisposable attach(this DispatcherUpdateMaster dum, IPrepareUpdateForDispatcher preparer) =>
|
||||
dum.attach(preparer, Dispatcher.CurrentDispatcher);
|
||||
}
|
||||
}
|
||||
@@ -156,15 +156,13 @@ namespace mbts.ui.shell
|
||||
public string name => _propname;
|
||||
|
||||
public void set(T value) {
|
||||
if (!Equals(value, _value)) {
|
||||
Changing?.Invoke(_value, value);
|
||||
var old = _value;
|
||||
_value = value;
|
||||
Changed?.Invoke(old, value);
|
||||
_owner.RaisePropertyChanged(_propname);
|
||||
}
|
||||
if (!Equals(value, _value))
|
||||
_apply_new_value(value);
|
||||
}
|
||||
|
||||
public IDisposable set_as_job(T value) =>
|
||||
Equals(value, _value) ? null : Disposable.Create(() => _apply_new_value(value));
|
||||
|
||||
public IDisposable Subscribe(IObserver<(T oldval, T newval)> observer) {
|
||||
Changed += pch;
|
||||
return Disposable.Create(() => Changed -= pch);
|
||||
@@ -182,6 +180,14 @@ namespace mbts.ui.shell
|
||||
get { return _value; }
|
||||
set { set(value); }
|
||||
}
|
||||
|
||||
void _apply_new_value(T new_value) {
|
||||
Changing?.Invoke(_value, new_value);
|
||||
var old = _value;
|
||||
_value = new_value;
|
||||
Changed?.Invoke(old, new_value);
|
||||
_owner.RaisePropertyChanged(_propname);
|
||||
}
|
||||
}
|
||||
|
||||
protected class DelegateProperty<T> : Property<T> {
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace mbts.spark {
|
||||
value = initial_value;
|
||||
}
|
||||
|
||||
event Action<(T oldval, T newval)> _value_set;
|
||||
public event Action<(T oldval, T newval)> value_set;
|
||||
|
||||
public T value { get; private set; }
|
||||
public string text => _text ?? (_text = _format(value));
|
||||
@@ -27,14 +27,22 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
public IDisposable on_next_distinct_as_job(T value, ref bool dirty) {
|
||||
if (!value.Equals(this.value)) {
|
||||
dirty = true;
|
||||
return Disposable.Create(() => OnNext(value));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void OnCompleted() { }
|
||||
public void OnError(Exception error) { }
|
||||
public void OnNext(T value) {
|
||||
if (_value_set != null) {
|
||||
if (value_set != null) {
|
||||
T prev = this.value;
|
||||
this.value = value;
|
||||
_text = null;
|
||||
_value_set.Invoke((prev, value));
|
||||
value_set.Invoke((prev, value));
|
||||
} else {
|
||||
this.value = value;
|
||||
_text = null;
|
||||
@@ -42,7 +50,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public IDisposable Subscribe(IObserver<(T oldval, T newval)> observer) =>
|
||||
Observable.FromEvent<Action<(T oldval, T newval)>, (T oldval, T newval)>(cb => _value_set += cb, cb => _value_set -= cb)
|
||||
Observable.FromEvent<Action<(T oldval, T newval)>, (T oldval, T newval)>(cb => value_set += cb, cb => value_set -= cb)
|
||||
.Subscribe(observer);
|
||||
}
|
||||
}
|
||||
@@ -386,7 +386,7 @@ namespace mbts.spark {
|
||||
void _tick() {
|
||||
if (_settings != null) {
|
||||
ulong unused = 0;
|
||||
bool last_trade_changed = _vm.md.get_last_trade(ref unused, out _last_trade, out DateTime _, out ulong __);
|
||||
bool last_trade_changed = _vm.md.get_last_trade(ref unused, out _last_trade, out ulong __);
|
||||
bool depth_changed = _vm.md.get_depth(ref _prices_updated, ref _bids, ref _asks);
|
||||
_mkt_break_lines.refresh();
|
||||
bool prices_changed =
|
||||
|
||||
@@ -275,7 +275,7 @@ namespace mbts.spark {
|
||||
_open.set(md.open_price);
|
||||
_settlement.set(md.settlement_price);
|
||||
ulong unused = 0;
|
||||
md.get_last_trade(ref unused, out NativePriceSize last, out DateTime time, out ulong volume);
|
||||
md.get_last_trade(ref unused, out NativePriceSize last, out ulong volume);
|
||||
if (!double.IsNaN(last.price)) {
|
||||
_change.set(last.price - md.settlement_price);
|
||||
} else {
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace mbts.spark {
|
||||
if (!sec_md.md.get_bbo(ref bbo_time, out NativePriceSize bid, out NativePriceSize ask)) return false;
|
||||
// last is only used in waterfall and last calculations, so if neither of those types are selected
|
||||
// we should not exit early if last is somehow not avaialble
|
||||
if (!sec_md.md.get_last_trade(ref last_trade_time, out NativePriceSize last, out DateTime unused1, out ulong unused2) && pnl_request.HasFlag(pnl_calc_type.waterfall | pnl_calc_type.last)) return false;
|
||||
if (!sec_md.md.get_last_trade(ref last_trade_time, out NativePriceSize last, out ulong unused2) && pnl_request.HasFlag(pnl_calc_type.waterfall | pnl_calc_type.last)) return false;
|
||||
|
||||
if (pnl_request.HasFlag(pnl_calc_type.waterfall)) {
|
||||
// last price is available and withing range of available bid and ask
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace mbts.spark.utilities
|
||||
internal interface ISecurityMDPump
|
||||
{
|
||||
IObservable<(double bid, uint bid_size, double ask, uint ask_size)> bbo { get; }
|
||||
IObservable<(double last, uint last_size, DateTime time_stamp, ulong volume)> last_trade { get; }
|
||||
IObservable<(double last, uint last_size, ulong volume)> last_trade { get; }
|
||||
IObservable<double> bid_price { get; }
|
||||
IObservable<uint> bid_size { get; }
|
||||
IObservable<double> ask_price { get; }
|
||||
@@ -61,7 +61,6 @@ namespace mbts.spark.utilities
|
||||
private double _bid_price, _ask_price, _last_price;
|
||||
private uint _bid_size, _ask_size, _last_size;
|
||||
private ulong _volume;
|
||||
private DateTime _last_time;
|
||||
|
||||
private bool _refresh_bbo(MDConsumerHandle md) {
|
||||
if (md.get_bbo(ref _bbo_ref, out NativePriceSize b, out NativePriceSize a)) {
|
||||
@@ -75,10 +74,9 @@ namespace mbts.spark.utilities
|
||||
}
|
||||
|
||||
private bool _refresh_last(MDConsumerHandle md) {
|
||||
if (md.get_last_trade(ref _last_ref, out NativePriceSize ps, out DateTime ts, out ulong v)) {
|
||||
if (md.get_last_trade(ref _last_ref, out NativePriceSize ps, out ulong v)) {
|
||||
_last_price = ps.price;
|
||||
_last_size = ps.size;
|
||||
_last_time = ts;
|
||||
_volume = v;
|
||||
return true;
|
||||
}
|
||||
@@ -86,17 +84,16 @@ namespace mbts.spark.utilities
|
||||
}
|
||||
|
||||
private (double, uint, double, uint) _select_bbo() { return (_bid_price, _bid_size, _ask_price, _ask_size); }
|
||||
private (double, uint, DateTime, ulong) _select_last() { return (_last_price, _last_size, _last_time, _volume); }
|
||||
private (double, uint, ulong) _select_last() { return (_last_price, _last_size, _volume); }
|
||||
|
||||
public IObservable<(double bid, uint bid_size, double ask, uint ask_size)> bbo => _bbo_pump.Select(_ => _select_bbo()).StartWith(_select_bbo());
|
||||
public IObservable<(double last, uint last_size, DateTime time_stamp, ulong volume)> last_trade => _last_pump.Select(_ => _select_last()).StartWith(_select_last());
|
||||
public IObservable<(double last, uint last_size, ulong volume)> last_trade => _last_pump.Select(_ => _select_last()).StartWith(_select_last());
|
||||
public IObservable<double> bid_price => _bbo_pump.Select(_ => _bid_price).DistinctUntilChanged().StartWith(_bid_price);
|
||||
public IObservable<uint> bid_size => _bbo_pump.Select(_ => _bid_size).DistinctUntilChanged().StartWith(_bid_size);
|
||||
public IObservable<double> ask_price => _bbo_pump.Select(_ => _ask_price).DistinctUntilChanged().StartWith(_ask_price);
|
||||
public IObservable<uint> ask_size => _bbo_pump.Select(_ => _ask_size).DistinctUntilChanged().StartWith(_ask_size);
|
||||
public IObservable<double> last_price => _bbo_pump.Select(_ => _last_price).DistinctUntilChanged().StartWith(_last_price);
|
||||
public IObservable<uint> last_size => _bbo_pump.Select(_ => _last_size).DistinctUntilChanged().StartWith(_last_size);
|
||||
public IObservable<DateTime> last_time => _last_pump.Select(_ => _last_time).DistinctUntilChanged().StartWith(_last_time);
|
||||
public IObservable<ulong> volume => _last_pump.Select(_ => _volume).DistinctUntilChanged().StartWith(_volume);
|
||||
public IObservable<double> session_low => _root_pump.Select(md => md.session_low).DistinctUntilChanged();
|
||||
public IObservable<double> session_high => _root_pump.Select(md => md.session_high).DistinctUntilChanged();
|
||||
|
||||
@@ -235,7 +235,7 @@ namespace mbts.spark.utilities {
|
||||
|
||||
public DynamicOrderDefinition dynamic_order() => new DynamicOrderDefinition
|
||||
{
|
||||
Child = custom_order(),
|
||||
//Child = custom_order(),
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ using System.Windows.Threading;
|
||||
namespace mbts.spark {
|
||||
static class WorkLoop {
|
||||
public const double default_excessive_cycle_ratio = 1.2;
|
||||
static readonly DispatcherPriority default_priority;
|
||||
static readonly TimeSpan default_interval;
|
||||
public static readonly TimeSpan default_interval;
|
||||
public static readonly DispatcherPriority default_priority;
|
||||
|
||||
static WorkLoop() {
|
||||
var timer_params = config.Configuration.get<bts.config.LadderKnobs>();
|
||||
|
||||
@@ -31,7 +31,8 @@ namespace bts {
|
||||
Mercury,
|
||||
Testing,
|
||||
Latency,
|
||||
DataFlow
|
||||
DataFlow,
|
||||
Plugin
|
||||
// Please keep this list in sync with logging.h/logging.cpp
|
||||
}
|
||||
readonly struct Logger {
|
||||
|
||||
@@ -72,7 +72,12 @@ namespace mbts.co2
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool get_last_trade(ref ulong time, out NativePriceSize ps, out DateTime timestamp, out ulong total_volume) {
|
||||
public bool get_last_trade(ref ulong time, out NativePriceSize ps, out ulong total_volume) {
|
||||
total_volume = _cold->total_volume;
|
||||
return (_cold->last_trade.load_if_new(ref time, out ps));
|
||||
}
|
||||
|
||||
public bool get_last_trade(ref ulong time, out NativePriceSize ps, out utils.LLDateTime timestamp, out ulong total_volume) {
|
||||
timestamp = _cold->last_trade_time;
|
||||
total_volume = _cold->total_volume;
|
||||
return (_cold->last_trade.load_if_new(ref time, out ps));
|
||||
@@ -88,15 +93,15 @@ namespace mbts.co2
|
||||
public ulong total_volume { get { return _cold->total_volume; } }
|
||||
|
||||
public double settlement_price { get { return _cold->settlement_price;} }
|
||||
public DateTime settlement_date { get { return _cold->settlement_date;} }
|
||||
public utils.LLDate settlement_date { get { return _cold->settlement_date;} }
|
||||
public double previous_settlement_price { get { return _cold->previous_settlement_price;} }
|
||||
public DateTime previous_settlement_date { get { return _cold->previous_settlement_date;} }
|
||||
public utils.LLDate previous_settlement_date { get { return _cold->previous_settlement_date;} }
|
||||
|
||||
public double open_price { get { return _cold->open_price;} }
|
||||
public DateTime open_date { get { return _cold->open_date; } }
|
||||
public utils.LLDate open_date { get { return _cold->open_date; } }
|
||||
|
||||
public double close_price { get { return _cold->close_price;} }
|
||||
public DateTime close_date { get { return _cold->close_date; } }
|
||||
public utils.LLDate close_date { get { return _cold->close_date; } }
|
||||
public double session_high { get { return _cold->session_high;} }
|
||||
public double session_low { get { return _cold->session_low; } }
|
||||
public double open_interest { get { return _cold->open_interest; } }
|
||||
|
||||
@@ -210,19 +210,24 @@ namespace mbts.co2.tests
|
||||
Assert.IsTrue(ask.size == 202);
|
||||
|
||||
time = 0;
|
||||
DateTime trade_date;
|
||||
ulong total_volume;
|
||||
NativePriceSize last_trade;
|
||||
Assert.IsTrue(handle.get_last_trade(ref time, out last_trade, out trade_date, out total_volume));
|
||||
Assert.IsTrue(handle.get_last_trade(ref time, out NativePriceSize last_trade, out utils.LLDateTime ll_trade_date, out ulong total_volume));
|
||||
// trade date
|
||||
DateTime trade_date = ll_trade_date;
|
||||
Assert.IsTrue(last_trade.price == 5.5 && last_trade.size == 505);
|
||||
Assert.IsTrue(trade_date.Year == 2015 && trade_date.Month == 9 && trade_date.Day == 22);
|
||||
Assert.IsTrue(total_volume == 4200);
|
||||
Assert.IsTrue(handle.settlement_date.Year == 2000 && handle.settlement_date.Day == 9 && handle.settlement_date.Month == 8);
|
||||
// settlement date
|
||||
DateTime settlement_dt = handle.settlement_date;
|
||||
Assert.IsTrue(settlement_dt.Year == 2000 && settlement_dt.Day == 9 && settlement_dt.Month == 8);
|
||||
Assert.IsTrue(handle.settlement_price == 6.6);
|
||||
Assert.IsTrue(handle.open_price == 7.7);
|
||||
Assert.IsTrue(handle.open_date.Year == 2001 && handle.open_date.Month == 1 && handle.open_date.Day == 2);
|
||||
// open date
|
||||
DateTime open_dt = handle.open_date;
|
||||
Assert.IsTrue(open_dt.Year == 2001 && open_dt.Month == 1 && open_dt.Day == 2);
|
||||
Assert.IsTrue(handle.close_price == 8.8);
|
||||
Assert.IsTrue(handle.close_date.Year == 2002 && handle.close_date.Month == 3 && handle.close_date.Day == 4);
|
||||
// close date
|
||||
DateTime close_dt = handle.close_date;
|
||||
Assert.IsTrue(close_dt.Year == 2002 && close_dt.Month == 3 && close_dt.Day == 4);
|
||||
|
||||
Assert.IsTrue(handle.session_high == 9.9);
|
||||
Assert.IsTrue(handle.session_low == 10.1);
|
||||
|
||||
@@ -1 +1 @@
|
||||
set(sources api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/services/AdminService.proto;api/services/ApiUnitTestService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MarketDataRelay.proto;api/services/OrderService.proto;api/services/OutOfProcessURLListener.proto;api/services/PersistenceService.proto;api/services/PositionService.proto;api/services/ShellDiagnosticService.proto;api/services/ShellLatencyService.proto;api/services/SyntheticSecurityService.proto;api/services/UserService.proto;api/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/Executor.conf;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/Symbols.conf;config/defaults/cpp_config.conf;config/defaults/dynamic_orders.conf;config/defaults/edge.conf;config/defaults/expiration_display_offset.conf;config/defaults/jetfix.conf;config/defaults/logging.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/ExchangeSimCfg.proto;config/protos/MarketData.proto;config/protos/Ports.proto;config/protos/Symbols.proto;config/protos/UI.proto;config/protos/cpp_config.proto;config/protos/dynamic_orders.proto;config/protos/environment.proto;config/protos/expiration_display_offset.proto;config/protos/jetfix.proto;config/protos/logging.proto;config/protos/orders_fills_cleanup.proto;config/protos/quickbus_cfg.proto;config/protos/spreader.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/toggles.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;jetfix/codec/FIXArray.cpp;jetfix/common/OutFIX.cpp;jetfix/connection/AsyncReader.cpp;jetfix/connection/IConnection.cpp;jetfix/connection/SocketConnection.cpp;jetfix/gateway/CoreGateway.cpp;jetfix/gateway/JetFIXGateway.cpp;jetfix/gateway/Session.cpp;jetfix/store/FIXFileStore.cpp;jetfix/store/session_name.cpp;jetfix/tests/async_reader_tests.cpp;jetfix/tests/decoding_tests.cpp;jetfix/tests/fix_encoding_stream_tests.cpp;jetfix/tests/fix_fragment_tests.cpp;jetfix/tests/jetfix_performance_tests.cpp;jetfix/tests/sample_fix.cpp;jetfix/tests/store_tests.cpp;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/Diag/MDPriceLantencyTester.cpp;md/Diag/ShmDumper.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MDRecoverableConsumer.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/md2_tests.cpp;md/test/synthetic_book_merge_tests.cpp;mercury/actors/Actor.cpp;mercury/broker/AsyncEventBroker.cpp;mercury/broker/CoreEventBroker.cpp;mercury/broker/IEventBroker.cpp;mercury/events/TimerEvent.cpp;mercury/mercury_utils/Executor.cpp;mercury/mercury_utils/IPollableActor.cpp;mercury/mercury_utils/mercury_common.cpp;mercury/synopsis/SynopsisBuilder.cpp;mercury/topics/ITopic.cpp;metrics/metrics.cpp;metrics/system_metrics.cpp;orderman/actors/AsyncFactory.cpp;orderman/actors/ExecutionGateway.cpp;orderman/actors/FillStore.cpp;orderman/actors/OrderStore.cpp;orderman/actors/SODPosition.cpp;orderman/actors/SecuritySrc.cpp;orderman/actors/ServiceBridge.cpp;orderman/actors/order_manager/OrderBuilder.cpp;orderman/actors/order_manager/OrderManager.cpp;orderman/actors/order_manager/OrderServicesData.cpp;orderman/events/CancelRejectEvent.cpp;orderman/events/NewExecutionReportEvent.cpp;orderman/limiter/LimitStore.cpp;orderman/limiter/Limiter.cpp;orderman/limiter/ProductLimitNode.cpp;orderman/limiter/ProductLimitTree.cpp;orderman/limiter/SecurityLimitNode.cpp;orderman/limiter/SecurityLimitTree.cpp;orderman/limiter/tests/limit_tests.cpp;orderman/order_factory/OrLine truncated
|
||||
set(sources api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/services/AdminService.proto;api/services/ApiUnitTestService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MarketDataAuxiliaryService.proto;api/services/MarketDataRelay.proto;api/services/OrderService.proto;api/services/OutOfProcessURLListener.proto;api/services/PersistenceService.proto;api/services/PositionService.proto;api/services/ShellDiagnosticService.proto;api/services/ShellLatencyService.proto;api/services/SyntheticSecurityService.proto;api/services/UserService.proto;api/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/Executor.conf;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/Symbols.conf;config/defaults/cme_reference_data.conf;config/defaults/dynamic_orders.conf;config/defaults/edge.conf;config/defaults/jetfix.conf;config/defaults/logging.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/ExchangeSimCfg.proto;config/protos/MarketData.proto;config/protos/Ports.proto;config/protos/Symbols.proto;config/protos/UI.proto;config/protos/cme_reference_data.proto;config/protos/dynamic_orders.proto;config/protos/environment.proto;config/protos/jetfix.proto;config/protos/logging.proto;config/protos/orders_fills_cleanup.proto;config/protos/quickbus_cfg.proto;config/protos/spreader.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/toggles.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;jetfix/codec/FIXArray.cpp;jetfix/common/OutFIX.cpp;jetfix/connection/AsyncReader.cpp;jetfix/connection/IConnection.cpp;jetfix/connection/SocketConnection.cpp;jetfix/gateway/CoreGateway.cpp;jetfix/gateway/JetFIXGateway.cpp;jetfix/gateway/Session.cpp;jetfix/store/FIXFileStore.cpp;jetfix/store/session_name.cpp;jetfix/tests/async_reader_tests.cpp;jetfix/tests/decoding_tests.cpp;jetfix/tests/fix_encoding_stream_tests.cpp;jetfix/tests/fix_fragment_tests.cpp;jetfix/tests/jetfix_performance_tests.cpp;jetfix/tests/sample_fix.cpp;jetfix/tests/store_tests.cpp;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/Diag/MDPriceLantencyTester.cpp;md/Diag/ShmDumper.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MDRecoverableConsumer.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/md2_tests.cpp;md/test/synthetic_book_merge_tests.cpp;mercury/actors/Actor.cpp;mercury/broker/AsyncEventBroker.cpp;mercury/broker/CoreEventBroker.cpp;mercury/broker/IEventBroker.cpp;mercury/events/TimerEvent.cpp;mercury/mercury_utils/Executor.cpp;mercury/mercury_utils/IPollableActor.cpp;mercury/mercury_utils/mercury_common.cpp;mercury/synopsis/SynopsisBuilder.cpp;mercury/topics/ITopic.cpp;metrics/metrics.cpp;metrics/system_metrics.cpp;orderman/actors/AsyncFactory.cpp;orderman/actors/ExecutionGateway.cpp;orderman/actors/FillStore.cpp;orderman/actors/OrderStore.cpp;orderman/actors/SODPosition.cpp;orderman/actors/SecuritySrc.cpp;orderman/actors/ServiceBridge.cpp;orderman/actors/order_manager/OrderBuilder.cpp;orderman/actors/order_manager/OrderManager.cpp;orderman/actors/order_manager/OrderServicesData.cpp;orderman/events/CancelRejectEvent.cpp;orderman/events/NewExecutionReportEvent.cpp;orderman/limiter/LimitStore.cpp;orderman/limiter/Limiter.cpp;orderman/limiter/ProductLimitNode.cpp;orderman/limiter/ProductLimitTree.cpp;orderman/limiter/SecurityLimitNode.cpp;orderman/limiter/SecurityLimitTree.cpp;orderman/limiter/tests/limit_tests.cpp;orderman/order_factory/DynamicOrderRegistry.cpp;ordermanLine truncated
|
||||
@@ -3,8 +3,6 @@ package bts.api.md.auxiliary;
|
||||
option csharp_namespace="bts.api.md.auxiliary";
|
||||
import "lib/api/apioptions.proto";
|
||||
import "lib/api/apicore.proto";
|
||||
import "lib/domain_model/Security.proto";
|
||||
import "lib/md/protos/co2.proto";
|
||||
|
||||
message VolumeAtPriceLevel{
|
||||
int32 record_id = 1 [(bts.api.key)=true];
|
||||
|
||||
@@ -6,6 +6,7 @@ import "lib/api/apioptions.proto";
|
||||
import "lib/domain_model/Security.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "lib/sparkproto/SparkProtos.proto";
|
||||
import "lib/api/apicore.proto";
|
||||
|
||||
service OrderService {
|
||||
option (bts.api.service_description)="Implements order management";
|
||||
@@ -15,9 +16,12 @@ service OrderService {
|
||||
rpc cancel_order(Cancel) returns (Response);
|
||||
rpc update_order(Update) returns (Response);
|
||||
rpc crack_order(Crack) returns (Response);
|
||||
rpc get_registered_dynamic_order_types(bts.api.VoidMessage) returns (RegisteredDynamicOrderTypes);
|
||||
|
||||
// streams
|
||||
rpc orders (OrdersSub) returns (stream OrderRecord);
|
||||
|
||||
|
||||
rpc fills (FillsSub) returns (stream Fill);
|
||||
}
|
||||
|
||||
@@ -139,8 +143,7 @@ message CoverOrderDefinition {
|
||||
}
|
||||
message DynamicOrderDefinition {
|
||||
string dynamic_order_type = 1;
|
||||
map<string,string> parameters = 2;
|
||||
CustomOrderDefinition child = 3;
|
||||
map<string, DynamicOrderParam> order_params = 2;
|
||||
}
|
||||
// End custom order definitions
|
||||
|
||||
@@ -259,7 +262,7 @@ message TopOrderState {}
|
||||
message TriggerOrderState {}
|
||||
message CoverOrderState {}
|
||||
message DynamicOrderState {
|
||||
map<string,string> state = 2;
|
||||
map<string,string> state = 1;
|
||||
}
|
||||
|
||||
enum OrderStatus {
|
||||
@@ -465,3 +468,76 @@ message TriggerExitCondition{
|
||||
uint32 timeout_seconds=20; //seconds
|
||||
bool conditional_cancel=30;
|
||||
}
|
||||
|
||||
|
||||
// Dynamic Orders
|
||||
|
||||
enum DynamicOrderPrimitiveDescriptor {
|
||||
DYNAMIC_ORDER_PRIMITIVE_INT = 0;
|
||||
DYNAMIC_ORDER_PRIMITIVE_UINT = 1;
|
||||
DYNAMIC_ORDER_PRIMITIVE_DOUBLE = 2;
|
||||
DYNAMIC_ORDER_PRIMITIVE_STRING = 3;
|
||||
DYNAMIC_ORDER_PRIMITIVE_BOOL = 4;
|
||||
DYNAMIC_ORDER_PRIMITIVE_ORDER_DEF = 5;
|
||||
}
|
||||
|
||||
message DynamicOrderTypeDescriptor {
|
||||
oneof descriptor {
|
||||
DynamicOrderPrimitiveDescriptor primitive = 2;
|
||||
DynamicOrderArrayDescriptor array = 3;
|
||||
DynamicOrderStructDescriptor structure = 4;
|
||||
DynamicOrderEnumeratedDescriptor enumerated = 5;
|
||||
}
|
||||
}
|
||||
|
||||
message DynamicOrderArrayDescriptor {
|
||||
DynamicOrderTypeDescriptor element_type = 1;
|
||||
}
|
||||
|
||||
message DynamicOrderParamDescriptor {
|
||||
string param_name = 1;
|
||||
DynamicOrderTypeDescriptor param_type = 2;
|
||||
}
|
||||
|
||||
message DynamicOrderStructDescriptor {
|
||||
repeated DynamicOrderParamDescriptor field = 1;
|
||||
}
|
||||
|
||||
message DynamicOrderEnumeratedDescriptor {
|
||||
repeated string element = 1;
|
||||
}
|
||||
|
||||
message DynamicOrderDescriptor {
|
||||
string dynamic_order_type = 1;
|
||||
repeated DynamicOrderParamDescriptor param_desc = 3;
|
||||
}
|
||||
|
||||
message RegisteredDynamicOrderTypes {
|
||||
repeated DynamicOrderDescriptor dynamic_order_desc = 1;
|
||||
}
|
||||
|
||||
message DynamicOrderParam {
|
||||
oneof value {
|
||||
uint32 as_int32 = 1;
|
||||
uint32 as_uint32 = 2;
|
||||
double as_double = 3;
|
||||
string as_string = 4;
|
||||
bool as_bool = 5;
|
||||
CustomOrderDefinition as_order_def = 6;
|
||||
DynamicOrderArray as_array = 7;
|
||||
DynamicOrderStruct as_struct = 8;
|
||||
DynamicOrderEnumerated as_enumerated = 9;
|
||||
}
|
||||
}
|
||||
|
||||
message DynamicOrderArray {
|
||||
repeated DynamicOrderParam element = 1;
|
||||
}
|
||||
|
||||
message DynamicOrderStruct {
|
||||
map<string,DynamicOrderParam> field = 1;
|
||||
}
|
||||
|
||||
message DynamicOrderEnumerated {
|
||||
string enum_value = 1;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -26,4 +26,8 @@ message OrdersSoftCleanup{
|
||||
|
||||
message ToastNotifications {
|
||||
optional bool enabled = 1 [default = false];
|
||||
}
|
||||
|
||||
message VolumeAtPrice{
|
||||
optional bool enabled = 1 [default = true];
|
||||
}
|
||||
@@ -116,6 +116,7 @@ void configure_logging(bts::config::Logging const&cfg)
|
||||
{log::Testing,"Testing"},
|
||||
{log::Latency,"Latency"},
|
||||
{log::DataFlow,"DataFlow"},
|
||||
{log::Plugin,"Plugin"},
|
||||
};
|
||||
|
||||
real_cfg.sinks["console"] =
|
||||
|
||||
@@ -42,6 +42,7 @@ constexpr log::Subsystem Mercury {ExSim.ordinal+1 };
|
||||
constexpr log::Subsystem Testing {Mercury.ordinal+1 };
|
||||
constexpr log::Subsystem Latency {Testing.ordinal+1 };
|
||||
constexpr log::Subsystem DataFlow {Latency.ordinal+1 };
|
||||
constexpr log::Subsystem Plugin {DataFlow.ordinal+1 };
|
||||
|
||||
struct LoggerHandle {
|
||||
LoggerHandle(LoggerHandle const&) = delete;
|
||||
|
||||
@@ -17,12 +17,12 @@ namespace orderman {
|
||||
|
||||
struct AsyncFactory::PImpl
|
||||
{
|
||||
PImpl() :
|
||||
PImpl(DynamicOrderRegistry const&b) :
|
||||
orders_stream(),
|
||||
fix_buffer_stream(),
|
||||
db(),
|
||||
order_router(),
|
||||
order_factory(db,order_router)
|
||||
order_factory(db,order_router,b)
|
||||
{}
|
||||
|
||||
mercury::Stream<CreateOrderReplyEvent> orders_stream;
|
||||
@@ -32,7 +32,7 @@ struct AsyncFactory::PImpl
|
||||
OrderFactory order_factory;
|
||||
};
|
||||
|
||||
AsyncFactory::AsyncFactory() : me(new PImpl()) {}
|
||||
AsyncFactory::AsyncFactory(DynamicOrderRegistry const&b) : me(new PImpl(b)) {}
|
||||
AsyncFactory::~AsyncFactory () {}
|
||||
|
||||
void AsyncFactory::init()
|
||||
|
||||
@@ -7,12 +7,13 @@
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
class DynamicOrderRegistry;
|
||||
|
||||
// used to asynchronously build fix buffers and orders
|
||||
class AsyncFactory : public mercury::Actor
|
||||
{
|
||||
public:
|
||||
AsyncFactory();
|
||||
AsyncFactory(DynamicOrderRegistry const&);
|
||||
~AsyncFactory();
|
||||
|
||||
void init() override;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "ServiceBridge.h"
|
||||
|
||||
#include "lib/api/public/ServiceContext.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
#include "lib/orderman/events/ActivateOrderEvent.h"
|
||||
#include "lib/orderman/events/CancelOrderEvent.h"
|
||||
#include "lib/orderman/events/CrackOrderEvent.h"
|
||||
#include "lib/orderman/events/NewAdminDataEvent.h"
|
||||
#include "lib/orderman/events/NewSecuritiesEvent.h"
|
||||
#include "lib/orderman/events/OrderManagerReadyEvent.h"
|
||||
#include "lib/orderman/events/StoredFillEvent.h"
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "lib/orderman/order_factory/OrderFactory.h"
|
||||
#include "lib/orderman/order_router/OrderRouter.h"
|
||||
#include "lib/orderman/securities/MapSecurityDB.h"
|
||||
#include "lib/orderman/events/NewAdminDataEvent.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
#include "lib/orderman/orderman_utils/orderman_common.h"
|
||||
@@ -24,12 +24,13 @@ namespace orderman {
|
||||
|
||||
struct ServiceBridge::PImpl {
|
||||
PImpl(OnReady const &on_ready, OnOrders const &on_orders,
|
||||
OnFills const &on_fills)
|
||||
OnFills const &on_fills,
|
||||
DynamicOrderRegistry const &dyn_order_registry)
|
||||
: on_ready(on_ready), on_orders(on_orders), on_fills(on_fills),
|
||||
have_orders(false), have_securities(false), order_manager_ready(false),
|
||||
sec_db(), order_router(), order_factory(sec_db, order_router),
|
||||
known_orders() {
|
||||
}
|
||||
sec_db(), order_router(),
|
||||
order_factory(sec_db, order_router, dyn_order_registry),
|
||||
known_orders() {}
|
||||
|
||||
OnReady on_ready;
|
||||
OnOrders on_orders;
|
||||
@@ -47,20 +48,18 @@ struct ServiceBridge::PImpl {
|
||||
mercury::Stream<NewAdminDataEvent> new_admin_data_pub;
|
||||
std::unordered_set<OrderKey> known_orders;
|
||||
std::vector<std::shared_ptr<const api::admin::AdminData>> admin_data_updates;
|
||||
|
||||
|
||||
std::promise<void> ready;
|
||||
};
|
||||
|
||||
ServiceBridge::ServiceBridge(OnReady const &on_ready, OnOrders const &on_orders,
|
||||
OnFills const &on_fills)
|
||||
: me(new PImpl(on_ready, on_orders, on_fills)) {}
|
||||
OnFills const &on_fills,
|
||||
DynamicOrderRegistry const &dyn_order_registry)
|
||||
: me(new PImpl(on_ready, on_orders, on_fills, dyn_order_registry)) {}
|
||||
|
||||
ServiceBridge::~ServiceBridge() {}
|
||||
|
||||
void ServiceBridge::block_until_ready()
|
||||
{
|
||||
me->ready.get_future().wait();
|
||||
}
|
||||
void ServiceBridge::block_until_ready() { me->ready.get_future().wait(); }
|
||||
|
||||
void ServiceBridge::init() {
|
||||
subscribe<NewAdminDataEvent>([this](auto const &u) { this->on(u); });
|
||||
@@ -125,8 +124,8 @@ void ServiceBridge::on(mercury::Update<OrderManagerReadyEvent> const &update) {
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceBridge::on(mercury::Update<NewAdminDataEvent> const&update) {
|
||||
if (update.events)
|
||||
void ServiceBridge::on(mercury::Update<NewAdminDataEvent> const &update) {
|
||||
if (update.events)
|
||||
for (auto ev : *(update.events))
|
||||
me->order_router.update(*ev.admin_data);
|
||||
}
|
||||
@@ -233,12 +232,12 @@ ServiceBridge::crack_order(api::orderman::Crack const &c) {
|
||||
return f.get();
|
||||
}
|
||||
|
||||
void ServiceBridge::update_admin_data(std::shared_ptr<const api::admin::AdminData> const&admin)
|
||||
{
|
||||
void ServiceBridge::update_admin_data(
|
||||
std::shared_ptr<const api::admin::AdminData> const &admin) {
|
||||
post_action([this, admin]() {
|
||||
me->admin_data_updates.push_back (admin);
|
||||
publish(me->new_admin_data_pub,*admin);
|
||||
});
|
||||
me->admin_data_updates.push_back(admin);
|
||||
publish(me->new_admin_data_pub, *admin);
|
||||
});
|
||||
}
|
||||
|
||||
bool ServiceBridge::is_ready() const {
|
||||
@@ -249,5 +248,5 @@ void ServiceBridge::maybe_signal_ready(bool old_ready) {
|
||||
if (!old_ready && is_ready())
|
||||
me->on_ready();
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -1,14 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "lib/mercury/actors/Actor.h"
|
||||
#include "lib/config/protos/jetfix.pb.h"
|
||||
#include "lib/mercury/actors/Actor.h"
|
||||
#include <memory>
|
||||
|
||||
// fwds
|
||||
namespace bts {
|
||||
namespace api {
|
||||
class ServiceContext;
|
||||
namespace admin { class AdminData;}
|
||||
namespace admin {
|
||||
class AdminData;
|
||||
}
|
||||
namespace orderman {
|
||||
class OrderRecord;
|
||||
class Fill;
|
||||
@@ -17,32 +19,36 @@ class Create;
|
||||
class Update;
|
||||
class Cancel;
|
||||
class Crack;
|
||||
}}
|
||||
} // namespace orderman
|
||||
} // namespace api
|
||||
namespace orderman {
|
||||
class StoredFillEvent;
|
||||
class StoredOrderEvent;
|
||||
class NewSecuritiesEvent;
|
||||
class OrderManagerReadyEvent;
|
||||
class NewAdminDataEvent;
|
||||
}}
|
||||
class DynamicOrderRegistry;
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
// end fwds
|
||||
|
||||
|
||||
// Provides a threading bridge between the quickbux/service world and
|
||||
// the mercury event broker.
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
class ServiceBridge : public mercury::Actor
|
||||
{
|
||||
public:
|
||||
template <class EV> using OnEv = std::function<void(EV const&)>;
|
||||
class ServiceBridge : public mercury::Actor {
|
||||
public:
|
||||
template <class EV> using OnEv = std::function<void(EV const &)>;
|
||||
|
||||
using OnReady = std::function<void()>;
|
||||
using OnOrders = std::function<void (std::vector<api::orderman::OrderRecord> const& )>;
|
||||
using OnFills = std::function<void (std::vector<api::orderman::Fill> const&)>;
|
||||
|
||||
ServiceBridge(OnReady const&, OnOrders const&, OnFills const&);
|
||||
using OnOrders =
|
||||
std::function<void(std::vector<api::orderman::OrderRecord> const &)>;
|
||||
using OnFills =
|
||||
std::function<void(std::vector<api::orderman::Fill> const &)>;
|
||||
|
||||
ServiceBridge(OnReady const &, OnOrders const &, OnFills const &,
|
||||
DynamicOrderRegistry const &);
|
||||
void init() override;
|
||||
~ServiceBridge();
|
||||
|
||||
@@ -50,23 +56,25 @@ public:
|
||||
void block_until_ready();
|
||||
|
||||
// these can be called from any thread, after block_until_ready() returns
|
||||
api::orderman::Response create_order(api::orderman::Create const&c);
|
||||
api::orderman::Response update_order(api::orderman::Update const&c);
|
||||
api::orderman::Response cancel_order(api::orderman::Cancel const&c);
|
||||
api::orderman::Response crack_order(api::orderman::Crack const&c);
|
||||
void update_admin_data(std::shared_ptr<api::admin::AdminData const> const &admin);
|
||||
|
||||
private:
|
||||
api::orderman::Response create_order(api::orderman::Create const &c);
|
||||
api::orderman::Response update_order(api::orderman::Update const &c);
|
||||
api::orderman::Response cancel_order(api::orderman::Cancel const &c);
|
||||
api::orderman::Response crack_order(api::orderman::Crack const &c);
|
||||
void
|
||||
update_admin_data(std::shared_ptr<api::admin::AdminData const> const &admin);
|
||||
|
||||
private:
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
bool is_ready () const;
|
||||
bool is_ready() const;
|
||||
void maybe_signal_ready(bool old_ready);
|
||||
|
||||
void on(mercury::Update<StoredFillEvent> const&);
|
||||
void on(mercury::Update<StoredOrderEvent> const&);
|
||||
void on(mercury::Update<NewSecuritiesEvent> const&);
|
||||
void on(mercury::Update<OrderManagerReadyEvent> const&);
|
||||
void on(mercury::Update<NewAdminDataEvent> const&);
|
||||
|
||||
void on(mercury::Update<StoredFillEvent> const &);
|
||||
void on(mercury::Update<StoredOrderEvent> const &);
|
||||
void on(mercury::Update<NewSecuritiesEvent> const &);
|
||||
void on(mercury::Update<OrderManagerReadyEvent> const &);
|
||||
void on(mercury::Update<NewAdminDataEvent> const &);
|
||||
};
|
||||
|
||||
}}
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -40,7 +40,8 @@ struct OrderManager::OrderInfo {
|
||||
};
|
||||
|
||||
struct OrderManager::PImpl {
|
||||
PImpl(Actor &owner) : state(State::WAIT_ADMIN), services_data(owner) {}
|
||||
PImpl(Actor &owner, DynamicOrderRegistry const &b)
|
||||
: state(State::WAIT_ADMIN), services_data(owner, b) {}
|
||||
|
||||
State state;
|
||||
std::unordered_map<OrderKey, OrderInfo> orders;
|
||||
@@ -50,7 +51,7 @@ struct OrderManager::PImpl {
|
||||
mercury::Stream<OrderManagerReadyEvent> pub_ready;
|
||||
};
|
||||
|
||||
OrderManager::OrderManager() : me(new PImpl(*this)) {}
|
||||
OrderManager::OrderManager(DynamicOrderRegistry const&b) : me(new PImpl(*this,b)) {}
|
||||
OrderManager::~OrderManager() {}
|
||||
|
||||
void OrderManager::init() {
|
||||
@@ -202,8 +203,7 @@ void OrderManager::on_activate_order(
|
||||
OrderInfo oi{*order, me->services_data};
|
||||
auto serv_ptr = oi.order_services.get();
|
||||
me->orders[k] = std::move(oi);
|
||||
order->on_activate(ev.price, ev.quantity, *serv_ptr,
|
||||
ev.trace);
|
||||
order->on_activate(ev.price, ev.quantity, *serv_ptr, ev.trace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,8 +213,7 @@ void OrderManager::on_update_order(const mercury::Update<UpdateOrderEvent> &m) {
|
||||
auto k = ev.key();
|
||||
auto it = me->orders.find(k);
|
||||
if (it != me->orders.end())
|
||||
it->second.order->on_update(ev.price, ev.quantity,
|
||||
ev.trace);
|
||||
it->second.order->on_update(ev.price, ev.quantity, ev.trace);
|
||||
else {
|
||||
LOG(OrderMan, Error,
|
||||
"Received an update request for an unknown order {}. "
|
||||
|
||||
@@ -22,6 +22,7 @@ class StoredFillEvent;
|
||||
class CreateFIXBufferReplyEvent;
|
||||
class GatewayStatusChangeEvent;
|
||||
class NewAdminDataEvent;
|
||||
class DynamicOrderRegistry;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +52,7 @@ namespace orderman {
|
||||
|
||||
class OrderManager : public mercury::Actor {
|
||||
public:
|
||||
OrderManager();
|
||||
OrderManager(DynamicOrderRegistry const&dyn_order_builder);
|
||||
~OrderManager();
|
||||
void init() override;
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
OrderServicesData::OrderServicesData(mercury::Actor &owner)
|
||||
: owner(owner), order_router(), order_factory(sec_db, order_router),
|
||||
OrderServicesData::OrderServicesData(mercury::Actor &owner,DynamicOrderRegistry const&b)
|
||||
: owner(owner), order_router(), order_factory(sec_db, order_router,b),
|
||||
last_timer_ev(
|
||||
Timer::now(),
|
||||
to<mercury::TimeStampStr>(datetime::FIX_timestamp(datetime::now()))) {
|
||||
|
||||
@@ -67,13 +67,14 @@ struct SessionServicesData {
|
||||
|
||||
class OrderServicesData {
|
||||
public:
|
||||
OrderServicesData(mercury::Actor &owner);
|
||||
OrderServicesData(mercury::Actor &owner,DynamicOrderRegistry const&b);
|
||||
|
||||
mercury::Actor &owner;
|
||||
securities::MapSecurityDB sec_db;
|
||||
OrderRouter order_router;
|
||||
Limiter limiter;
|
||||
OrderFactory order_factory;
|
||||
|
||||
|
||||
std::unique_ptr<mercury::ContentSubscription<BookUpdateEvent>> md_subs;
|
||||
std::unique_ptr<
|
||||
mercury::ContentSubscription<OrderStateUpdateEvent, ParentKey>>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
class DynamicOrder;
|
||||
|
||||
using DynamicOrderBuilder = std::function<std::unique_ptr<DynamicOrder>()>;
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,45 @@
|
||||
#include "DynamicOrderRegistry.h"
|
||||
#include "lib/orderman/orders/DynamicOrder.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
struct DynamicOrderRegistry::PImpl {
|
||||
std::unordered_map<
|
||||
std::string,
|
||||
std::pair<DynamicOrderBuilder, api::orderman::DynamicOrderDescriptor>>
|
||||
dyn_orders;
|
||||
};
|
||||
|
||||
DynamicOrderRegistry::DynamicOrderRegistry() : me(new PImpl()) {}
|
||||
DynamicOrderRegistry::~DynamicOrderRegistry() {}
|
||||
|
||||
void DynamicOrderRegistry::register_dynamic_order(
|
||||
api::orderman::DynamicOrderDescriptor const &desc,
|
||||
DynamicOrderBuilder const &b) {
|
||||
me->dyn_orders[desc.dynamic_order_type()] = std::make_pair(b, desc);
|
||||
}
|
||||
|
||||
std::unique_ptr<DynamicOrder>
|
||||
DynamicOrderRegistry::build(std::string const &dynamic_order_type) const {
|
||||
auto it = me->dyn_orders.find(dynamic_order_type);
|
||||
if (it != me->dyn_orders.end())
|
||||
return it->second.first();
|
||||
else
|
||||
return std::unique_ptr<DynamicOrder>();
|
||||
}
|
||||
|
||||
std::vector<api::orderman::DynamicOrderDescriptor>
|
||||
DynamicOrderRegistry::get_all_dynamic_order_types() const {
|
||||
|
||||
std::vector<api::orderman::DynamicOrderDescriptor> result;
|
||||
for (auto const &ot : me->dyn_orders)
|
||||
result.push_back(ot.second.second);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/orderman/order_factory/DynamicOrderBuilder.h"
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
|
||||
class DynamicOrderRegistry {
|
||||
public:
|
||||
DynamicOrderRegistry();
|
||||
~DynamicOrderRegistry();
|
||||
|
||||
void register_dynamic_order(api::orderman::DynamicOrderDescriptor const&desc,
|
||||
DynamicOrderBuilder const&builder);
|
||||
|
||||
// can return a null if no such order type exists
|
||||
std::unique_ptr<DynamicOrder> build(std::string const&dynamic_order_type) const;
|
||||
|
||||
std::vector<api::orderman::DynamicOrderDescriptor> get_all_dynamic_order_types() const;
|
||||
private:
|
||||
struct PImpl;
|
||||
std::unique_ptr <PImpl> me;
|
||||
};
|
||||
|
||||
}}
|
||||
@@ -1,24 +1,25 @@
|
||||
#include "OrderFactory.h"
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/orderman/orderman_utils/ExecutionReport.h"
|
||||
#include "lib/orderman/orders/PreActivationOrderServices.h"
|
||||
#include "lib/utils/Puid.h"
|
||||
#include "lib/utils/SpinLock.h"
|
||||
#include "lib/utils/bts_assert.h"
|
||||
#include "lib/orderman/orderman_utils/ExecutionReport.h"
|
||||
#include "lib/orderman/orders/PreActivationOrderServices.h"
|
||||
|
||||
// order types
|
||||
#include "lib/orderman/order_factory/DynamicOrderRegistry.h"
|
||||
#include "lib/orderman/orders/DynamicOrder.h"
|
||||
#include "lib/orderman/orders/IcebergOrder.h"
|
||||
#include "lib/orderman/orders/spreader_orders/SpreaderOrder.h"
|
||||
#include "lib/orderman/orders/NativeOrder.h"
|
||||
#include "lib/orderman/orders/TimeBoxOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/TickOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/LeanOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/JoinOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/TopOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/CoverOrder.h"
|
||||
#include "lib/orderman/orders/TriggerOrder.h"
|
||||
#include "lib/orderman/orders/DynamicOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/CoverOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/JoinOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/LeanOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/TickOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/TopOrder.h"
|
||||
#include "lib/orderman/orders/spreader_orders/SpreaderOrder.h"
|
||||
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
@@ -48,16 +49,20 @@ OrderKey gen_order_id() {
|
||||
}
|
||||
|
||||
struct OrderFactory::PImpl {
|
||||
PImpl(securities::ISecurityDB &db,OrderRouter const&router)
|
||||
: my_orders(), sec_db(db), router(router){}
|
||||
PImpl(securities::ISecurityDB &db, OrderRouter const &router,
|
||||
DynamicOrderRegistry const &dr)
|
||||
: my_orders(), sec_db(db), router(router), dynamic_order_registry(dr) {}
|
||||
|
||||
std::vector<std::unique_ptr<Order>> my_orders;
|
||||
securities::ISecurityDB &sec_db;
|
||||
OrderRouter const&router;
|
||||
OrderRouter const &router;
|
||||
DynamicOrderRegistry const &dynamic_order_registry;
|
||||
};
|
||||
|
||||
OrderFactory::OrderFactory(securities::ISecurityDB &db, OrderRouter const&router)
|
||||
: me(new PImpl(db, router)) {}
|
||||
OrderFactory::OrderFactory(securities::ISecurityDB &db,
|
||||
OrderRouter const &router,
|
||||
DynamicOrderRegistry const ®istry)
|
||||
: me(new PImpl(db, router, registry)) {}
|
||||
|
||||
OrderFactory::~OrderFactory() {}
|
||||
|
||||
@@ -66,8 +71,8 @@ Order &OrderFactory::create(OrderKey parent,
|
||||
auto k = gen_order_id();
|
||||
auto pk = parent;
|
||||
auto &order = allocate(k, pk, def);
|
||||
order.on_init_new(def,
|
||||
PreActivationOrderServices{me->sec_db, *this,me->router});
|
||||
order.on_init_new(def,
|
||||
PreActivationOrderServices{me->sec_db, *this, me->router});
|
||||
return order;
|
||||
}
|
||||
|
||||
@@ -76,7 +81,7 @@ Order &OrderFactory::recover(api::orderman::OrderRecord const &rec) {
|
||||
auto pk = OrderKey(rec.parent_key());
|
||||
auto &order = allocate(k, pk, rec.def());
|
||||
order.on_init_recovered(
|
||||
rec, PreActivationOrderServices{me->sec_db, *this,me->router});
|
||||
rec, PreActivationOrderServices{me->sec_db, *this, me->router});
|
||||
return order;
|
||||
}
|
||||
|
||||
@@ -90,7 +95,7 @@ Order &OrderFactory::recreate_from_exe_report(ExecutionReport const &r) {
|
||||
case NATIVE_ORDER_TYPE_STOP_LIMIT: {
|
||||
auto native_order = std::make_unique<NativeOrder>();
|
||||
native_order->on_init_from_exe_report(
|
||||
r, PreActivationOrderServices{me->sec_db, *this,me->router});
|
||||
r, PreActivationOrderServices{me->sec_db, *this, me->router});
|
||||
native_order->_key = r.order_key;
|
||||
native_order->_parent_key = null_order_key();
|
||||
me->my_orders.emplace_back();
|
||||
@@ -122,32 +127,40 @@ Order &OrderFactory::allocate(OrderKey k, OrderKey pk,
|
||||
order_ptr.reset(new IcebergOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kSpreader:
|
||||
order_ptr.reset (new orderman::SpreaderOrder());
|
||||
order_ptr.reset(new orderman::SpreaderOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kTimeBox:
|
||||
order_ptr.reset (new orderman::TimeBoxOrder());
|
||||
order_ptr.reset(new orderman::TimeBoxOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kTick:
|
||||
order_ptr.reset (new orderman::TickOrder());
|
||||
order_ptr.reset(new orderman::TickOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kLean:
|
||||
order_ptr.reset (new orderman::LeanOrder());
|
||||
break;
|
||||
order_ptr.reset(new orderman::LeanOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kJoin:
|
||||
order_ptr.reset (new orderman::JoinOrder());
|
||||
order_ptr.reset(new orderman::JoinOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kTop:
|
||||
order_ptr.reset (new orderman::TopOrder());
|
||||
order_ptr.reset(new orderman::TopOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kTrigger:
|
||||
order_ptr.reset (new orderman::TriggerOrder());
|
||||
order_ptr.reset(new orderman::TriggerOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kCover:
|
||||
order_ptr.reset (new orderman::CoverOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kDynamic:
|
||||
order_ptr.reset (new orderman::DynamicOrder());
|
||||
order_ptr.reset(new orderman::CoverOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kDynamic: {
|
||||
order_ptr = me->dynamic_order_registry.build(
|
||||
def.custom_def().dynamic().dynamic_order_type());
|
||||
if (!order_ptr) {
|
||||
// the default dynamic order is empty and will transition
|
||||
// immediately to an error state, so we use it when we cannot
|
||||
// resolve the requested type
|
||||
order_ptr.reset(new orderman::DynamicOrder());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CustomOrderDefinition::CUSTOM_NOT_SET:
|
||||
bts_assert(false);
|
||||
break;
|
||||
@@ -156,5 +169,5 @@ Order &OrderFactory::allocate(OrderKey k, OrderKey pk,
|
||||
order_ptr->_parent_key = pk;
|
||||
return *order_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -11,7 +11,8 @@ class ISecurityDB;
|
||||
}
|
||||
namespace orderman {
|
||||
class Order;
|
||||
}
|
||||
class DynamicOrderRegistry;
|
||||
} // namespace orderman
|
||||
namespace orderman {
|
||||
class OrderRouter;
|
||||
}
|
||||
@@ -32,7 +33,8 @@ namespace orderman {
|
||||
|
||||
class OrderFactory : public IOrderFactory {
|
||||
public:
|
||||
OrderFactory(securities::ISecurityDB &db, OrderRouter const &router);
|
||||
OrderFactory(securities::ISecurityDB &db, OrderRouter const &router,
|
||||
DynamicOrderRegistry const &dynamic_order_reg);
|
||||
~OrderFactory();
|
||||
|
||||
Order &create(OrderKey parent,
|
||||
|
||||
@@ -15,7 +15,6 @@ struct DynamicOrder::PImpl {
|
||||
api::orderman::OrderState state;
|
||||
};
|
||||
|
||||
|
||||
DynamicOrder::DynamicOrder() : me(new PImpl()) {}
|
||||
|
||||
DynamicOrder::~DynamicOrder() {}
|
||||
@@ -27,13 +26,14 @@ api::orderman::OrderDefinition const &DynamicOrder::definition() const {
|
||||
void DynamicOrder::on_init_new(api::orderman::OrderDefinition const &def,
|
||||
const PreActivationOrderServices &) {
|
||||
me->def = def;
|
||||
me->state.mutable_trigger();
|
||||
me->state.mutable_dynamic();
|
||||
|
||||
auto const &dynamic_def = def.custom_def().dynamic();
|
||||
auto msg = fmt::format("Could not find implementation for dynamic order type {}",
|
||||
dynamic_def.dynamic_order_type());
|
||||
auto msg =
|
||||
fmt::format("Could not find implementation for dynamic order type {}",
|
||||
dynamic_def.dynamic_order_type());
|
||||
me->state.set_status(ORDER_STATUS_REJECTED_BY_SPARK);
|
||||
me->state.set_last_msg(msg);
|
||||
transition(ORDER_STATUS_REJECTED_BY_SPARK, msg);
|
||||
}
|
||||
|
||||
void DynamicOrder::on_init_recovered(api::orderman::OrderRecord const &rec,
|
||||
@@ -41,35 +41,21 @@ void DynamicOrder::on_init_recovered(api::orderman::OrderRecord const &rec,
|
||||
auto const &def = rec.def();
|
||||
me->def = def;
|
||||
me->state = rec.state();
|
||||
auto msg = fmt::format("Could not find implementation for dynamic order type {}",
|
||||
def.custom_def().dynamic().dynamic_order_type());
|
||||
transition(ORDER_STATUS_ERROR, msg);
|
||||
}
|
||||
|
||||
void DynamicOrder::on_activate(Price , Quantity , OrderServices &services,
|
||||
PerfTrace const&) {
|
||||
bts_assert(!me->services);
|
||||
me->services = &services;
|
||||
report_state();
|
||||
}
|
||||
|
||||
void DynamicOrder::on_update(Price , Quantity , PerfTrace const&) {}
|
||||
void DynamicOrder::on_crack(PerfTrace const&) {}
|
||||
void DynamicOrder::on_cancel(PerfTrace const&) {}
|
||||
|
||||
void DynamicOrder::transition(api::orderman::OrderStatus new_status,
|
||||
std::string const &msg) {
|
||||
auto const &from = OrderStatus_Name(me->state.status());
|
||||
auto const &to = OrderStatus_Name(new_status);
|
||||
LOG(OrderMan, Info, "Transitioning dynamic order {} from {} to {}. Msg: {}",
|
||||
key().value(), from, to, msg);
|
||||
auto msg =
|
||||
fmt::format("Could not find implementation for dynamic order type {}",
|
||||
def.custom_def().dynamic().dynamic_order_type());
|
||||
me->state.set_status(ORDER_STATUS_REJECTED_BY_SPARK);
|
||||
me->state.set_last_msg(msg);
|
||||
me->state.set_status(new_status);
|
||||
}
|
||||
|
||||
void DynamicOrder::report_state() {
|
||||
me->services->report_state(me->state);
|
||||
void DynamicOrder::on_activate(Price, Quantity, OrderServices &services,
|
||||
PerfTrace const &) {
|
||||
services.report_state(me->state);
|
||||
}
|
||||
|
||||
void DynamicOrder::on_update(Price, Quantity, PerfTrace const &) {}
|
||||
void DynamicOrder::on_crack(PerfTrace const &) {}
|
||||
void DynamicOrder::on_cancel(PerfTrace const &) {}
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -25,8 +25,6 @@ public:
|
||||
void on_cancel(PerfTrace const&) override ;
|
||||
|
||||
private:
|
||||
void report_state();
|
||||
void transition(api::orderman::OrderStatus new_state,std::string const&msg);
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
};
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
.separator ","
|
||||
create table trace (md integer,spreader_on_book integer,event_type text,md_src integer,event_id integer,spreader_modify_order integer,order_update integer,fix_socket_r integer,spreader_on_child_order_update integer,md_sn integer,s2s_us integer,fix_socket_w integer,exe_gw integer);
|
||||
.import trace.csv trace
|
||||
create view tick_to_order as select
|
||||
event_id,
|
||||
(fix_socket_w - md) / 1000 total,
|
||||
(md_src-md)/1000 md_to_md_src,
|
||||
(spreader_on_book-md_src)/1000 md_src_to_spreader,
|
||||
(spreader_modify_order-spreader_on_book)/1000 spreader_on_book_to_modify_order,
|
||||
(order_update-spreader_modify_order)/1000 spreader_modify_order_to_native_order,
|
||||
(exe_gw-order_update)/1000 native_order_to_gw,
|
||||
(fix_socket_w - exe_gw)/1000 gw_to_socket
|
||||
from trace where md<>0 and total < 3000 and spreader_modify_order<>0;
|
||||
File diff suppressed because it is too large.
Load diff
Binary file not shown.
@@ -10,7 +10,8 @@ def gen_create_table(d,t):
|
||||
fields = [ "%s integer" % k if isinstance (v,int) else "%s text" % k for (k,v) in d.iteritems()]
|
||||
print ".separator \",\"\ncreate table trace (%s);" % ",".join(fields)
|
||||
print ".import %s trace" % t
|
||||
print '''create view tick_to_order as select
|
||||
print '''
|
||||
create view tick_to_order as select
|
||||
event_id,
|
||||
order_key,
|
||||
(fix_socket_w - md) / 1000 total,
|
||||
@@ -19,8 +20,21 @@ def gen_create_table(d,t):
|
||||
(spreader_modify_order-spreader_on_book)/1000 spreader_on_book_to_modify_order,
|
||||
(order_update-spreader_modify_order)/1000 spreader_modify_order_to_native_order,
|
||||
(exe_gw-order_update)/1000 native_order_to_gw,
|
||||
(fix_socket_w - exe_gw)/1000 gw_to_socket
|
||||
from trace where md<>0 and total < 3000 and spreader_modify_order<>0;'''
|
||||
(fix_socket_w - exe_gw)/1000 gw_to_socket
|
||||
from trace where md<>0 and total < 3000 and spreader_modify_order<>0;
|
||||
|
||||
create view tick_to_order_perc as select
|
||||
event_id,
|
||||
total,
|
||||
round(100.0*md_to_md_src/total) md_to_md_src ,
|
||||
round(100.0*md_src_to_spreader/total) md_src_to_spreader ,
|
||||
round(100.0*spreader_on_book_to_modify_order/total) spreader_on_book_to_modify_order ,
|
||||
round(100.0*spreader_modify_order_to_native_order/total) spreader_modify_order_to_native_order ,
|
||||
round(100.0*native_order_to_gw/total) native_order_to_gw ,
|
||||
round(100.0*gw_to_socket/total) gw_to_socket
|
||||
from tick_to_order;
|
||||
|
||||
'''
|
||||
|
||||
def gen_insert(d):
|
||||
values = [ "%s" % v if isinstance (v,int) else "'%s'" % v for v in d.values()]
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
#include "lib/orderman/actors/SecuritySrc.h"
|
||||
#include "lib/orderman/actors/ServiceBridge.h"
|
||||
#include "lib/orderman/actors/order_manager/OrderManager.h"
|
||||
#include "lib/orderman/order_factory/DynamicOrderRegistry.h"
|
||||
#include "lib/utils/bts_chrono.h"
|
||||
#include "lib/plugin/plugin.h"
|
||||
#include "lib/plugin/SparkServices.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
@@ -24,6 +27,7 @@ namespace orderman {
|
||||
struct OrderServiceServer::PImpl {
|
||||
PImpl(bts::api::ServiceContext &ctx,
|
||||
std::shared_ptr<api::ISyntheticSecurityService> &ss,
|
||||
DynamicOrderRegistry const &d,
|
||||
metrics::MetricsContainer &stats)
|
||||
: fast_broker(std::make_shared<mercury::AsyncEventBroker>()),
|
||||
slow_broker(std::make_shared<mercury::AsyncEventBroker>()),
|
||||
@@ -31,7 +35,7 @@ struct OrderServiceServer::PImpl {
|
||||
fast_thread(), slow_thread(), service_ready(false), known_orders(),
|
||||
known_fills(), publish_orders(), publish_fills(),
|
||||
admin_service(ctx.locate<api::admin::AdminService>()), md_consumer(ss),
|
||||
stats(stats) {}
|
||||
stats(stats), dyn_order_registry(d) {}
|
||||
|
||||
std::shared_ptr<mercury::AsyncEventBroker> fast_broker;
|
||||
std::shared_ptr<mercury::AsyncEventBroker> slow_broker;
|
||||
@@ -49,14 +53,16 @@ struct OrderServiceServer::PImpl {
|
||||
api::admin::AdminService admin_service;
|
||||
bts::md::MDConsumer md_consumer;
|
||||
metrics::MetricsContainer &stats;
|
||||
DynamicOrderRegistry const &dyn_order_registry;
|
||||
};
|
||||
|
||||
OrderServiceServer::OrderServiceServer(
|
||||
bts::api::ServiceContext &ctx,
|
||||
std::shared_ptr<api::ISyntheticSecurityService> &ss,
|
||||
DynamicOrderRegistry const&d,
|
||||
metrics::MetricsContainer &stats)
|
||||
: api::orderman::OrderServiceBase(ctx), me(new PImpl(ctx, ss, stats)) {
|
||||
|
||||
: api::orderman::OrderServiceBase(ctx), me(new PImpl(ctx, ss, d,stats)) {
|
||||
|
||||
me->publish_orders = make_orders_publisher();
|
||||
me->publish_fills = make_fills_publisher();
|
||||
|
||||
@@ -69,18 +75,20 @@ OrderServiceServer::OrderServiceServer(
|
||||
|
||||
[this, &ctx](auto const &fill) {
|
||||
ctx.post([this, fill] { this->on_fills(fill); });
|
||||
});
|
||||
},
|
||||
|
||||
me->dyn_order_registry);
|
||||
|
||||
me->fast_broker->init_neighbours({me->slow_broker});
|
||||
me->slow_broker->init_neighbours({me->fast_broker});
|
||||
|
||||
// fast actors
|
||||
me->fast_exe.spawn<MDSource>(me->md_consumer, me->stats);
|
||||
me->fast_exe.spawn<OrderManager>();
|
||||
me->fast_exe.spawn<OrderManager>(me->dyn_order_registry);
|
||||
|
||||
auto &all_connections = config::get<config::JetFIX>().connection();
|
||||
for (auto const &c : all_connections)
|
||||
me->fast_exe.spawn<ExecutionGateway>(c,stats);
|
||||
me->fast_exe.spawn<ExecutionGateway>(c, stats);
|
||||
|
||||
me->fast_thread = std::thread([this]() {
|
||||
os::set_thread_name("fast_exe");
|
||||
@@ -105,7 +113,7 @@ OrderServiceServer::OrderServiceServer(
|
||||
// slow actors
|
||||
me->slow_exe.activate(me->service_bridge);
|
||||
me->slow_exe.spawn<mercury::Timer>();
|
||||
me->slow_exe.spawn<AsyncFactory>();
|
||||
me->slow_exe.spawn<AsyncFactory>(me->dyn_order_registry);
|
||||
me->slow_exe.spawn<OrderStore>();
|
||||
me->slow_exe.spawn<FillStore>();
|
||||
me->slow_exe.spawn<SecuritySrc>(me->md_consumer);
|
||||
@@ -225,5 +233,17 @@ void OrderServiceServer::crack_order(
|
||||
response = me->service_bridge->crack_order(crack);
|
||||
r(response);
|
||||
}
|
||||
|
||||
void OrderServiceServer::get_registered_dynamic_order_types(
|
||||
const api::VoidMessage &,
|
||||
const api::Response<api::orderman::RegisteredDynamicOrderTypes> &r) {
|
||||
api::orderman::RegisteredDynamicOrderTypes response;
|
||||
|
||||
auto all_orders = me->dyn_order_registry.get_all_dynamic_order_types();
|
||||
for (auto const &desc : all_orders)
|
||||
*response.add_dynamic_order_desc() = desc;
|
||||
r(response);
|
||||
}
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -1,39 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
#include "lib/api/services/OrderService.server.pb.h"
|
||||
#include "lib/mercury/mercury_utils/IPollableActor.h"
|
||||
#include <memory>
|
||||
|
||||
namespace bts {
|
||||
namespace api { class ISyntheticSecurityService; }
|
||||
namespace metrics {class MetricsContainer;}
|
||||
namespace api {
|
||||
class ISyntheticSecurityService;
|
||||
}
|
||||
namespace metrics {
|
||||
class MetricsContainer;
|
||||
}
|
||||
namespace orderman {
|
||||
class DynamicOrderRegistry;
|
||||
|
||||
|
||||
class OrderServiceServer : public api::orderman::OrderServiceBase
|
||||
{
|
||||
public:
|
||||
OrderServiceServer (bts::api::ServiceContext& context,
|
||||
std::shared_ptr<api::ISyntheticSecurityService>&,
|
||||
metrics::MetricsContainer &);
|
||||
class OrderServiceServer : public api::orderman::OrderServiceBase {
|
||||
public:
|
||||
OrderServiceServer(bts::api::ServiceContext &context,
|
||||
std::shared_ptr<api::ISyntheticSecurityService> &,
|
||||
DynamicOrderRegistry const&,
|
||||
metrics::MetricsContainer &);
|
||||
~OrderServiceServer();
|
||||
|
||||
void create_order(const api::orderman::Create&,
|
||||
const api::Response<api::orderman::Response>&) override;
|
||||
void cancel_order(const api::orderman::Cancel&,
|
||||
const api::Response<api::orderman::Response>&) override;
|
||||
void update_order(const api::orderman::Update&,
|
||||
const api::Response<api::orderman::Response>&) override;
|
||||
void crack_order(const api::orderman::Crack&,
|
||||
const api::Response<api::orderman::Response>& ) override;
|
||||
private:
|
||||
void create_order(const api::orderman::Create &,
|
||||
const api::Response<api::orderman::Response> &) override;
|
||||
void cancel_order(const api::orderman::Cancel &,
|
||||
const api::Response<api::orderman::Response> &) override;
|
||||
void update_order(const api::orderman::Update &,
|
||||
const api::Response<api::orderman::Response> &) override;
|
||||
void crack_order(const api::orderman::Crack &,
|
||||
const api::Response<api::orderman::Response> &) override;
|
||||
void get_registered_dynamic_order_types(
|
||||
const api::VoidMessage &,
|
||||
const api::Response<api::orderman::RegisteredDynamicOrderTypes> &)
|
||||
override;
|
||||
|
||||
private:
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
void on_orders(std::vector<api::orderman::OrderRecord> const&);
|
||||
void on_fills (std::vector<api::orderman::Fill> const&);
|
||||
void on_orders(std::vector<api::orderman::OrderRecord> const &);
|
||||
void on_fills(std::vector<api::orderman::Fill> const &);
|
||||
};
|
||||
|
||||
|
||||
|
||||
}}
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "SparkServices.h"
|
||||
#include "lib/orderman/order_factory/DynamicOrderRegistry.h"
|
||||
|
||||
namespace bts {
|
||||
|
||||
using namespace orderman;
|
||||
|
||||
struct SparkServices::PImpl {
|
||||
PImpl(orderman::DynamicOrderRegistry &r) : dyn_order_registry(r) {}
|
||||
DynamicOrderRegistry &dyn_order_registry;
|
||||
};
|
||||
|
||||
SparkServices::SparkServices(orderman::DynamicOrderRegistry &r)
|
||||
: me(new PImpl(r)) {}
|
||||
|
||||
SparkServices::~SparkServices() {}
|
||||
|
||||
void SparkServices::register_dynamic_order(
|
||||
api::orderman::DynamicOrderDescriptor const &desc,
|
||||
std::function<std::unique_ptr<DynamicOrder>()> const &builder) {
|
||||
me->dyn_order_registry.register_dynamic_order(desc, builder);
|
||||
}
|
||||
|
||||
extern "C" void initialize_spark_plugin(SparkServices &) {}
|
||||
|
||||
} // namespace bts
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace bts {
|
||||
|
||||
namespace orderman {
|
||||
class DynamicOrder;
|
||||
class DynamicOrderRegistry;
|
||||
} // namespace orderman
|
||||
|
||||
class SparkServices {
|
||||
public:
|
||||
SparkServices(orderman::DynamicOrderRegistry &);
|
||||
~SparkServices();
|
||||
|
||||
void register_dynamic_order(
|
||||
api::orderman::DynamicOrderDescriptor const &desc,
|
||||
std::function<std::unique_ptr<orderman::DynamicOrder>()> const &builder);
|
||||
|
||||
private:
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
};
|
||||
} // namespace bts
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/orderman/actors/order_manager/OrderBuilder.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
#include "lib/plugin/SparkServices.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/dll.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
|
||||
namespace bts {
|
||||
namespace plugin {
|
||||
|
||||
using namespace bts::orderman;
|
||||
|
||||
void init_plugins(SparkServices &services) {
|
||||
|
||||
static std::vector<decltype (boost::dll::import<void (SparkServices&)>(boost::filesystem::path(),""))> keep_alive;
|
||||
|
||||
auto plugin_path = os::sparkd_wd() + "/plugins/";
|
||||
if (!boost::filesystem::is_directory(plugin_path)) {
|
||||
LOG(Plugin, Info,
|
||||
"No plugin directory found at {}. Skipping plugin loading",
|
||||
plugin_path);
|
||||
return;
|
||||
}
|
||||
|
||||
boost::filesystem::directory_iterator end;
|
||||
for (auto iter = boost::filesystem::directory_iterator(plugin_path);
|
||||
iter != end; ++iter) {
|
||||
auto &f = *iter;
|
||||
|
||||
auto pl = f.path().string();
|
||||
LOG(Plugin, Info, "Attempting to initialize plugin {}", pl);
|
||||
try {
|
||||
auto init_plugin = boost::dll::import<void(SparkServices &)>(
|
||||
f.path(), "init_spark_plugin");
|
||||
init_plugin(services);
|
||||
keep_alive.push_back(init_plugin);
|
||||
LOG(Plugin, Info, "Successfully initialized plugin {}", pl);
|
||||
} catch (boost::system::system_error const &e) {
|
||||
LOG(Plugin, Error,
|
||||
"Failed to initialize plugin {}. Error: {} (OS error code: {})",
|
||||
pl, std::string(e.what()), e.code());
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace plugin
|
||||
} // namespace bts
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace bts {
|
||||
class SparkServices;
|
||||
namespace plugin {
|
||||
void init_plugins(SparkServices &);
|
||||
}}
|
||||
@@ -7,8 +7,9 @@ add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/sdk
|
||||
COMMENT "Building SDK"
|
||||
DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/make_sdk.sh
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/example/build_example.sh
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/example/example.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/build_examples.sh
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/md_publisher_example.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/order_plugin_example.cpp
|
||||
server_layout)
|
||||
|
||||
add_custom_target(sdk_dir ALL DEPENDS ${CMAKE_BINARY_DIR}/sdk)
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
g++ -isystem ../externals/include \
|
||||
-I ../include \
|
||||
-I ../include/spark \
|
||||
-o example \
|
||||
example.cpp \
|
||||
-Wl,-rpath,../lib \
|
||||
-L ../lib \
|
||||
-l spark \
|
||||
-llttng-ust \
|
||||
-ldl
|
||||
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
g++ -isystem ../externals/include \
|
||||
-I ../include \
|
||||
-I ../include/spark \
|
||||
-o md_publisher_example \
|
||||
md_publisher_example.cpp \
|
||||
-Wl,-rpath,../lib \
|
||||
-L ../lib \
|
||||
-l spark \
|
||||
-llttng-ust \
|
||||
-ldl
|
||||
|
||||
g++ -isystem ../externals/include \
|
||||
-I ../include \
|
||||
-I ../include/spark \
|
||||
-fPIC \
|
||||
-g \
|
||||
-shared \
|
||||
-o order_plugin_example.so \
|
||||
order_plugin_example.cpp \
|
||||
-Wl,-rpath,.. \
|
||||
-L ../lib \
|
||||
-l spark
|
||||
File renamed without changes.
@@ -0,0 +1,385 @@
|
||||
#include "spark/lib/logging/logging.h"
|
||||
#include "spark/lib/orderman/orders/DynamicOrder.h"
|
||||
#include "spark/lib/plugin/SparkServices.h"
|
||||
#include "spark/lib/orderman/actors/order_manager/ChildOrder.h"
|
||||
#include "spark/lib/orderman/actors/order_manager/OrderBuilder.h"
|
||||
#include "spark/lib/orderman/orders/DynamicOrder.h"
|
||||
#include "spark/lib/utils/PBUtils.h"
|
||||
|
||||
using namespace bts::api::orderman;
|
||||
using namespace bts::orderman;
|
||||
|
||||
namespace bts {
|
||||
namespace order_example {
|
||||
|
||||
class DynamicIcebergOrder : public DynamicOrder {
|
||||
public:
|
||||
DynamicIcebergOrder();
|
||||
~DynamicIcebergOrder();
|
||||
OrderDefinition const &definition() const override;
|
||||
void on_init_new(OrderDefinition const &,
|
||||
const PreActivationOrderServices &) override;
|
||||
void on_init_recovered(OrderRecord const &,
|
||||
const PreActivationOrderServices &) override;
|
||||
void on_activate(Price, Quantity, OrderServices &,
|
||||
PerfTrace const &) override;
|
||||
void on_update(Price, Quantity, PerfTrace const &) override;
|
||||
void on_crack(PerfTrace const &) override;
|
||||
void on_cancel(PerfTrace const &) override;
|
||||
|
||||
private:
|
||||
void report_state();
|
||||
void send_next_child_order();
|
||||
|
||||
void merge_states(OrderState const &iceberg_state,
|
||||
OrderState const &child_state, OrderState *merged);
|
||||
|
||||
void on_child_order_update(OrderStateUpdateEvent const &);
|
||||
void transition(OrderStatus new_state, std::string const &msg);
|
||||
void transition(OrderStatus new_state);
|
||||
|
||||
struct ActiveChild;
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
};
|
||||
|
||||
struct DynamicIcebergOrder::ActiveChild {
|
||||
ActiveChild() {}
|
||||
ChildOrder order;
|
||||
api::orderman::OrderState state;
|
||||
void clear() { state = api::orderman::OrderState(); }
|
||||
};
|
||||
|
||||
struct DynamicIcebergOrder::PImpl {
|
||||
PImpl() : services(nullptr), child() {}
|
||||
|
||||
OrderServices *services;
|
||||
api::orderman::OrderDefinition def;
|
||||
api::orderman::OrderState state;
|
||||
OrderBuilder child_builder;
|
||||
ActiveChild child;
|
||||
Quantity show_quantity;
|
||||
};
|
||||
|
||||
DynamicIcebergOrder::DynamicIcebergOrder() : me(new PImpl()) {}
|
||||
DynamicIcebergOrder::~DynamicIcebergOrder() {}
|
||||
api::orderman::OrderDefinition const &DynamicIcebergOrder::definition() const {
|
||||
return me->def;
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::on_init_new(
|
||||
api::orderman::OrderDefinition const &def,
|
||||
const PreActivationOrderServices &services) {
|
||||
me->def = def;
|
||||
me->state.mutable_dynamic();
|
||||
|
||||
auto const &iceberg_def = def.custom_def().dynamic();
|
||||
me->show_quantity =
|
||||
Quantity(iceberg_def.order_params().at("show_size").as_uint32());
|
||||
|
||||
auto child_def = def;
|
||||
*child_def.mutable_custom_def() =
|
||||
iceberg_def.order_params().at("child").as_order_def();
|
||||
if (me->show_quantity.value() != 0) {
|
||||
me->child_builder = OrderBuilder(
|
||||
key(), child_def, services,
|
||||
std::max((size_t)1, (size_t)(me->show_quantity).value() / 10));
|
||||
transition(ORDER_STATUS_INACTIVE);
|
||||
} else {
|
||||
auto msg = fmt::format("Show quantity must be greater than 0");
|
||||
me->state.set_last_msg(msg);
|
||||
transition(ORDER_STATUS_REJECTED_BY_SPARK, msg);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::on_init_recovered(
|
||||
api::orderman::OrderRecord const &rec, const PreActivationOrderServices &) {
|
||||
auto const &def = rec.def();
|
||||
me->def = def;
|
||||
me->state = rec.state();
|
||||
|
||||
switch (me->state.status()) {
|
||||
|
||||
case ORDER_STATUS_WORKING:
|
||||
case ORDER_STATUS_DISCONNECTED: {
|
||||
auto msg = "System restarted with active iceberg order";
|
||||
me->state.set_last_msg(msg);
|
||||
transition(ORDER_STATUS_ERROR, msg);
|
||||
break;
|
||||
}
|
||||
// terminal states
|
||||
case ORDER_STATUS_ERROR:
|
||||
case ORDER_STATUS_REJECTED_BY_SPARK:
|
||||
case ORDER_STATUS_COMPLETED:
|
||||
case ORDER_STATUS_CANCELED:
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
case ORDER_STATUS_INACTIVE:
|
||||
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
bts_assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::on_activate(Price p, Quantity q,
|
||||
OrderServices &services,
|
||||
PerfTrace const &) {
|
||||
bts_assert(!me->services);
|
||||
me->services = &services;
|
||||
me->child_builder.activate(services);
|
||||
|
||||
switch (me->state.status()) {
|
||||
case ORDER_STATUS_INACTIVE:
|
||||
me->state.set_price(p.value());
|
||||
me->state.set_quantity(q.value());
|
||||
services.child_updates.sub(
|
||||
key(), [this](auto const &os) { this->on_child_order_update(os); });
|
||||
transition(ORDER_STATUS_WORKING);
|
||||
send_next_child_order();
|
||||
break;
|
||||
|
||||
// these are not possible since the on_init_recovered code
|
||||
// would have transitioned us to error already
|
||||
case ORDER_STATUS_WORKING:
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
case ORDER_STATUS_DISCONNECTED: {
|
||||
bts_assert(false);
|
||||
break;
|
||||
}
|
||||
// terminal states
|
||||
case ORDER_STATUS_ERROR:
|
||||
case ORDER_STATUS_REJECTED_BY_SPARK:
|
||||
case ORDER_STATUS_COMPLETED:
|
||||
case ORDER_STATUS_CANCELED:
|
||||
break;
|
||||
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
bts_assert(false);
|
||||
break;
|
||||
}
|
||||
report_state();
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::on_update(Price p, Quantity q, PerfTrace const &) {
|
||||
switch (me->state.status()) {
|
||||
case ORDER_STATUS_WORKING:
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
LOG(Plugin, Info,
|
||||
"Updating DynamicIceberg order {} to price {} quantity {}",
|
||||
key().value(), p.value(), q.value());
|
||||
me->state.set_price(p.value());
|
||||
me->state.set_quantity(q.value());
|
||||
break;
|
||||
case ORDER_STATUS_DISCONNECTED:
|
||||
case ORDER_STATUS_REJECTED_BY_SPARK:
|
||||
case ORDER_STATUS_COMPLETED:
|
||||
case ORDER_STATUS_CANCELED:
|
||||
case ORDER_STATUS_ERROR:
|
||||
transition(me->state.status(), "Cannot update order");
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_INACTIVE:
|
||||
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
bts_assert(false);
|
||||
break;
|
||||
}
|
||||
report_state();
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::on_crack(PerfTrace const &) {}
|
||||
|
||||
void DynamicIcebergOrder::on_cancel(PerfTrace const &) {
|
||||
switch (me->state.status()) {
|
||||
case ORDER_STATUS_WORKING:
|
||||
LOG(Plugin, Info, "Canceling DynamicIceberg Order {}", key().value());
|
||||
me->child.order.cancel();
|
||||
transition(ORDER_STATUS_CANCELED);
|
||||
break;
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
case ORDER_STATUS_DISCONNECTED:
|
||||
case ORDER_STATUS_REJECTED_BY_SPARK:
|
||||
case ORDER_STATUS_COMPLETED:
|
||||
case ORDER_STATUS_CANCELED:
|
||||
case ORDER_STATUS_ERROR:
|
||||
transition(me->state.status(), "Cannot cancel order");
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_INACTIVE:
|
||||
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
bts_assert(false);
|
||||
break;
|
||||
}
|
||||
report_state();
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::report_state() {
|
||||
if (me->child.state.filled_quantity()) {
|
||||
api::orderman::OrderState merged_state;
|
||||
merge_states(me->state, me->child.state, &merged_state);
|
||||
me->services->report_state(merged_state);
|
||||
} else
|
||||
me->services->report_state(me->state);
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::merge_states(
|
||||
api::orderman::OrderState const &iceberg_state,
|
||||
api::orderman::OrderState const &child_state,
|
||||
api::orderman::OrderState *merged) {
|
||||
auto child_order_fills = child_state.filled_quantity();
|
||||
auto child_order_avg_price = child_state.avg_price();
|
||||
auto child_order_last_price = child_state.last_price();
|
||||
|
||||
auto iceberg_fills = iceberg_state.filled_quantity();
|
||||
auto iceberg_avg_price = iceberg_state.avg_price();
|
||||
|
||||
*merged = iceberg_state;
|
||||
merged->set_filled_quantity(child_order_fills + iceberg_fills);
|
||||
merged->set_last_price(child_order_last_price);
|
||||
merged->set_avg_price((child_order_fills * child_order_avg_price +
|
||||
iceberg_fills * iceberg_avg_price) /
|
||||
(child_order_fills + iceberg_fills));
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::send_next_child_order() {
|
||||
bts_assert(me->state.quantity() > me->state.filled_quantity());
|
||||
|
||||
auto remaining = me->state.quantity() - me->state.filled_quantity();
|
||||
auto to_send = std::min(remaining, me->show_quantity.value());
|
||||
me->child.order = me->child_builder.build();
|
||||
LOG(Plugin, Info,
|
||||
"DynamicIceberg order {} creating new child order {} with size "
|
||||
"{} price {}. Filled {} so far out of {}",
|
||||
key().value(), me->child.order.key().value(), to_send, me->state.price(),
|
||||
me->state.filled_quantity(), me->state.quantity());
|
||||
|
||||
me->child.order.activate(Price(me->state.price()), Quantity(to_send));
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::on_child_order_update(
|
||||
OrderStateUpdateEvent const &ev) {
|
||||
switch (me->state.status()) {
|
||||
case ORDER_STATUS_WORKING:
|
||||
if (ev.key == me->child.order.key()) {
|
||||
me->child.state = ev.state;
|
||||
|
||||
switch (ev.state.status()) {
|
||||
|
||||
case ORDER_STATUS_WORKING:
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
// nothing to do but report new state
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_COMPLETED: {
|
||||
api::orderman::OrderState merged_state;
|
||||
merge_states(me->state, me->child.state, &merged_state);
|
||||
me->state = merged_state;
|
||||
me->child.clear();
|
||||
if (me->state.quantity() > me->state.filled_quantity())
|
||||
send_next_child_order();
|
||||
else
|
||||
transition(ORDER_STATUS_COMPLETED);
|
||||
break;
|
||||
}
|
||||
|
||||
case ORDER_STATUS_CANCELED:
|
||||
LOG(Plugin, Info,
|
||||
"Unexpected cancel of child {} in DynamicIceberg Order {}. "
|
||||
"Canceling parent",
|
||||
ev.key.value(), key().value());
|
||||
transition(ORDER_STATUS_CANCELED);
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_DISCONNECTED:
|
||||
case ORDER_STATUS_REJECTED_BY_SPARK:
|
||||
case ORDER_STATUS_ERROR:
|
||||
me->child.clear();
|
||||
transition(ORDER_STATUS_ERROR, "Unexpected child order state");
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_INACTIVE:
|
||||
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
bts_assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
LOG(Plugin, Info,
|
||||
"DynamicIceberg order {} received update for non active child "
|
||||
"order{} . update state = {} ",
|
||||
key().value(), me->child.order.key().value(),
|
||||
utils::pb::to_string(ev.state));
|
||||
}
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_CANCELED:
|
||||
case ORDER_STATUS_ERROR:
|
||||
case ORDER_STATUS_DISCONNECTED:
|
||||
case ORDER_STATUS_COMPLETED:
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
case ORDER_STATUS_REJECTED_BY_SPARK:
|
||||
case ORDER_STATUS_INACTIVE:
|
||||
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
bts_assert(false);
|
||||
break;
|
||||
}
|
||||
report_state();
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::transition(api::orderman::OrderStatus new_status,
|
||||
std::string const &msg) {
|
||||
auto const &from = OrderStatus_Name(me->state.status());
|
||||
auto const &to = OrderStatus_Name(new_status);
|
||||
LOG(Plugin, Info,
|
||||
"Transitioning dynamic iceberg order {} from {} to {}. Msg: {}",
|
||||
key().value(), from, to, msg);
|
||||
me->state.set_last_msg(msg);
|
||||
me->state.set_status(new_status);
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::transition(api::orderman::OrderStatus new_status) {
|
||||
auto const &from = OrderStatus_Name(me->state.status());
|
||||
auto const &to = OrderStatus_Name(new_status);
|
||||
LOG(OrderMan, Info, "Transitioning dynamic iceberg order {} from {} to {}",
|
||||
key().value(), from, to);
|
||||
me->state.set_status(new_status);
|
||||
}
|
||||
|
||||
|
||||
} // namespace order_example
|
||||
} // namespace bts
|
||||
|
||||
DynamicOrderDescriptor get_dynamic_iceberg_order_desc()
|
||||
{
|
||||
DynamicOrderDescriptor desc;
|
||||
|
||||
// order type name
|
||||
desc.set_dynamic_order_type("DynamicIcebergOrder");
|
||||
|
||||
// show size
|
||||
auto param = desc.add_param_desc();
|
||||
param->set_param_name("show_size");
|
||||
param->mutable_param_type()->set_primitive(DYNAMIC_ORDER_PRIMITIVE_UINT);
|
||||
|
||||
// child order
|
||||
param = desc.add_param_desc();
|
||||
param->set_param_name("child");
|
||||
param->mutable_param_type()->set_primitive(DYNAMIC_ORDER_PRIMITIVE_ORDER_DEF);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
extern "C" void init_spark_plugin(bts::SparkServices &serv) {
|
||||
using namespace bts;
|
||||
|
||||
serv.register_dynamic_order(get_dynamic_iceberg_order_desc(),
|
||||
[]() { return std::make_unique<bts::order_example::DynamicIcebergOrder>(); });
|
||||
LOG(Plugin,Info, "Initialized order_plugin_example.so");
|
||||
}
|
||||
+5
-5
@@ -23,10 +23,10 @@ ln -sf $2/../../externals/linux/include $1/sdk/externals/include
|
||||
ln -sf $2/../../externals/linux/lib/Release $1/sdk/externals/lib
|
||||
|
||||
ln -sf $1/server $1/sdk/lib
|
||||
mkdir $1/sdk/example
|
||||
cp $2/example/* $1/sdk/example
|
||||
ln -sf $1/sdk/lib/defaults $1/sdk/example/defaults
|
||||
chmod +x $1/sdk/example/build_example.sh
|
||||
(cd $1/sdk/example && ./build_example.sh && ./example >/dev/null && rm example)
|
||||
mkdir $1/sdk/examples
|
||||
cp $2/examples/* $1/sdk/examples
|
||||
ln -sf $1/sdk/lib/defaults $1/sdk/examples/defaults
|
||||
chmod +x $1/sdk/examples/build_examples.sh
|
||||
(cd $1/sdk/examples && ./build_examples.sh && ./md_publisher_example >/dev/null)
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/bin/bash
|
||||
if [ ! -f spark_sdk.tgz ]; then
|
||||
wget http://jenkins/job/Spark_Server/lastSuccessfulBuild/artifact/spark_sdk_1909.tgz -O spark_sdk.tgz
|
||||
fi
|
||||
|
||||
if [ ! -d spark_sdk ]; then
|
||||
git clone git@bitbucket.org:bluetradesys/spark_sdk.git
|
||||
else
|
||||
(cd spark_sdk && git pull)
|
||||
fi
|
||||
|
||||
rm -rf new_sdk
|
||||
mkdir new_sdk
|
||||
(cd new_sdk && tar -xvzf ../spark_sdk.tgz)
|
||||
cp -R new_sdk/* spark_sdk
|
||||
|
||||
# http://jenkins/job/Spark_Server/lastSuccessfulBuild/artifact/spark_server_1909.tgz
|
||||
# http://jenkins/job/Spark_Server/lastSuccessfulBuild/artifact/spark_sdk_1909.tgz
|
||||
@@ -1 +1 @@
|
||||
set(sources bts_trace.cpp;cmds/AutoCert.cpp;cmds/Benchmark.cpp;cmds/CmdRegistry.cpp;cmds/ConfigCheck.cpp;cmds/Help.cpp;cmds/Md.cpp;cmds/QuickTest.cpp;cmds/Run.cpp;cmds/RunSim.cpp;cmds/Span.cpp;cmds/Test.cpp;cmds/TestCeloxica.cpp;cmds/Web.cpp;dspark/mirage/quick_queue/quick_queue.cpp;exchange_sim/ExchangeSim.cpp;exchange_sim/ExchangeSimApplication.cpp;exchange_sim/book/Book.cpp;exchange_sim/book/ExchangeSim.proto;exchange_sim/book/Order.cpp;exchange_sim/book/OrderMatcher.cpp;exchange_sim/book/book_transform.cpp;exchange_sim/tests/test_book_transform.cpp;http/ApiGateway.cpp;http/WebServer.cpp;main.cpp;md/platforms/celoxica/CXListener.cpp;md/platforms/celoxica/CXMain.cpp;md/platforms/celoxica/tests/cx_tests.cpp;md/platforms/mdp3_onixs/MDP3Listener.cpp;md/platforms/mdp3_onixs/MDP3Main.cpp;md/platforms/mdp3_onixs/tests/mdp3_tests.cpp;md/run_md.cpp;position/IMarginObserver.cpp;position/IPositionObserver.cpp;position/MarginServiceCore.cpp;position/PositionServiceCore.cpp;position/PositionServiceServer.cpp;position/tests/PositionTests.cpp;support/ErrorReportService.cpp;support/ShellLatencyServer.cpp;user/AdminServiceServer.cpp;user/UserServiceServer.cpp;user/tests/admin_service_tests.cpp)
|
||||
set(sources bts_trace.cpp;cmds/AutoCert.cpp;cmds/Benchmark.cpp;cmds/CmdRegistry.cpp;cmds/ConfigCheck.cpp;cmds/Help.cpp;cmds/Md.cpp;cmds/QuickTest.cpp;cmds/Run.cpp;cmds/RunSim.cpp;cmds/Span.cpp;cmds/Test.cpp;cmds/TestCeloxica.cpp;cmds/Web.cpp;dspark/mirage/quick_queue/quick_queue.cpp;exchange_sim/ExchangeSim.cpp;exchange_sim/ExchangeSimApplication.cpp;exchange_sim/book/Book.cpp;exchange_sim/book/ExchangeSim.proto;exchange_sim/book/Order.cpp;exchange_sim/book/OrderMatcher.cpp;exchange_sim/book/book_transform.cpp;exchange_sim/tests/test_book_transform.cpp;http/ApiGateway.cpp;http/WebServer.cpp;main.cpp;md/ChannelVolume.cpp;md/MarketDataAuxiliaryServiceServer.cpp;md/VolumeAtPriceState.cpp;md/platforms/celoxica/CXListener.cpp;md/platforms/celoxica/CXMain.cpp;md/platforms/celoxica/tests/cx_tests.cpp;md/platforms/mdp3_onixs/MDP3Listener.cpp;md/platforms/mdp3_onixs/MDP3Main.cpp;md/platforms/mdp3_onixs/tests/mdp3_tests.cpp;md/run_md.cpp;position/IMarginObserver.cpp;position/IPositionObserver.cpp;position/MarginServiceCore.cpp;position/PositionServiceCore.cpp;position/PositionServiceServer.cpp;position/tests/PositionTests.cpp;support/ErrorReportService.cpp;support/ShellLatencyServer.cpp;user/AdminServiceServer.cpp;user/UserServiceServer.cpp;user/tests/admin_service_tests.cpp)
|
||||
@@ -21,8 +21,13 @@
|
||||
#include "lib/metrics/metrics.h"
|
||||
#include "lib/metrics/system_metrics.h"
|
||||
#include "server/sparkd/user/AdminServiceServer.h"
|
||||
#include "server/sparkd/md/MarketDataAuxiliaryServiceServer.h"
|
||||
#include "server/sparkd/user/UserServiceServer.h"
|
||||
#include "server/sparkd/position/PositionServiceServer.h"
|
||||
#include "lib/orderman/order_factory/DynamicOrderRegistry.h"
|
||||
#include "lib/plugin/SparkServices.h"
|
||||
#include "lib/plugin/plugin.h"
|
||||
#include "lib/config/protos/toggles.pb.h"
|
||||
|
||||
#include "lib/md/relay/QueryServer.h"
|
||||
|
||||
@@ -36,6 +41,7 @@ int Run::execute(std::vector<std::string> const &) {
|
||||
LOG(Gen, Warn, "------------------------------------ Sparkd launched "
|
||||
"--------------------------------");
|
||||
|
||||
|
||||
config::QuickbusNodeCfg qb_cfg;
|
||||
auto& ports = config::get<config::Ports>();
|
||||
qb_cfg.set_my_port(ports.qbus_port());
|
||||
@@ -53,9 +59,18 @@ int Run::execute(std::vector<std::string> const &) {
|
||||
std::make_shared<api::synthetic::SyntheticSecurityService>(sc);
|
||||
md::QueryServerPtr md_query_server(
|
||||
md::run_query_server(sc, synthetic_service, stats));
|
||||
orderman::OrderServiceServer order_service_server(sc, synthetic_service,stats);
|
||||
|
||||
// initialize order plugins
|
||||
orderman::DynamicOrderRegistry dyn_order_registry;
|
||||
SparkServices plugin_services(dyn_order_registry);
|
||||
plugin::init_plugins(plugin_services);
|
||||
// finished initializing order plugins
|
||||
|
||||
orderman::OrderServiceServer order_service_server(sc, synthetic_service,dyn_order_registry,stats);
|
||||
support::ErrorReportServer error_report_service(sc);
|
||||
admin::AdminServiceServer admin_service(sc);
|
||||
if(config::get<config::toggles::VolumeAtPrice>().enabled())
|
||||
md::auxiliary::MarketDataAuxiliaryServiceServer md_aux_server(sc);
|
||||
position::PositionServiceServer position_service(sc);
|
||||
metrics::ShellLatencyServer shell_latency_service(sc, stats, utils::Dispatcher::background());
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "ChannelVolume.h"
|
||||
#include "lib/api/services/MarketDataRelay.pb.h"
|
||||
#include "lib/md/PriceSize.h"
|
||||
|
||||
namespace bts{
|
||||
namespace md{
|
||||
namespace auxiliary{
|
||||
|
||||
using namespace bts::co2;
|
||||
using namespace bts::api::md::auxiliary;
|
||||
|
||||
ChannelVolume::ChannelVolume(SecurityChannel* channel)
|
||||
:
|
||||
_channel(channel){
|
||||
}
|
||||
|
||||
const VolumeAtPriceLevel& ChannelVolume::add_trade(const TradeMessage& m,
|
||||
int& record_id){
|
||||
auto price_map_it=_sec_map.find(m.key());
|
||||
if(price_map_it==_sec_map.end()){
|
||||
_sec_map[m.key()]=std::unordered_map<uint64_t,VolumeAtPriceLevel>();
|
||||
price_map_it=_sec_map.find(m.key());
|
||||
}
|
||||
auto& price_map=price_map_it->second;
|
||||
auto price_it=price_map.find(m.mantissa());
|
||||
if(price_it==price_map.end()){
|
||||
VolumeAtPriceLevel vol;
|
||||
vol.set_record_id(record_id++);
|
||||
vol.set_security_id(m.key());
|
||||
auto p = md::PriceSize(m.mantissa(),m.exponent(),0);
|
||||
vol.set_price(p.price());
|
||||
price_map[m.mantissa()] = vol;
|
||||
price_it=price_map.find(m.mantissa());
|
||||
}
|
||||
VolumeAtPriceLevel& vol=price_it->second;
|
||||
vol.set_volume(vol.volume()+m.size());
|
||||
return vol;
|
||||
}
|
||||
|
||||
bool ChannelVolume::match_update(const SecurityChannel& channel){
|
||||
if(_channel->type()==channel.type() &&
|
||||
_channel->exchange()==channel.exchange() &&
|
||||
_channel->symbol()==channel.symbol()){
|
||||
_channel->CopyFrom(channel);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}}}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "lib/api/services/MarketDataAuxiliaryService.pb.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace bts{
|
||||
namespace co2 {class TradeMessage;class SecurityChannel;}
|
||||
namespace md{
|
||||
namespace auxiliary{
|
||||
|
||||
// volume at the various price levels for all
|
||||
// securities belonging to a single channel.
|
||||
class ChannelVolume{
|
||||
private:
|
||||
bts::co2::SecurityChannel* const _channel;
|
||||
std::unordered_map<uint32_t,std::unordered_map<uint64_t,bts::api::md::auxiliary::VolumeAtPriceLevel>> _sec_map;
|
||||
public:
|
||||
ChannelVolume(bts::co2::SecurityChannel* channel);
|
||||
// finds the VolumeAtPriceLevel for the <sec, price_level>
|
||||
// in the trade and updates the volume. if <sec,price_level>
|
||||
// is not found, it increases the record_id before assigning
|
||||
// it to VolumeAtPriceLevel's record_id
|
||||
const bts::api::md::auxiliary::VolumeAtPriceLevel&
|
||||
add_trade(const bts::co2::TradeMessage& m, int& record_id);
|
||||
// if the channel is matched, it updated with it with
|
||||
// the data in the arg, and returns true
|
||||
bool match_update(const bts::co2::SecurityChannel& channel);
|
||||
};
|
||||
}}}
|
||||
@@ -4,6 +4,10 @@
|
||||
#include "lib/api/public/ServiceContext.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
#include "lib/utils/Dispatcher.h"
|
||||
#include "lib/md/get_symbols.h"
|
||||
#include "VolumeAtPriceState.h"
|
||||
#include "lib/utils/bts_chrono.h"
|
||||
|
||||
namespace bts{
|
||||
namespace md{
|
||||
@@ -13,27 +17,59 @@ using namespace bts::co2;
|
||||
using namespace bts::api::md::auxiliary;
|
||||
|
||||
struct MarketDataAuxiliaryServiceServer::PImpl{
|
||||
MarketDataAuxiliaryServiceBase::Volume_at_priceStatefulPublisher publisher;
|
||||
MarketDataRelay relay_service;
|
||||
int id;
|
||||
MarketDataAuxiliaryServiceBase::Volume_at_priceStatefulPublisher publisher;
|
||||
std::unique_ptr<utils::DispatcherTimer> trade_timer;
|
||||
int64_t poll_period_ms;
|
||||
VolumeAtPriceState state;
|
||||
PImpl(bts::api::ServiceContext& context,
|
||||
const MarketDataAuxiliaryServiceBase::Volume_at_priceStatefulPublisher& publisher)
|
||||
:
|
||||
publisher(publisher),
|
||||
:
|
||||
relay_service(context.locate<MarketDataRelay>()),
|
||||
id(0)
|
||||
{
|
||||
publisher(publisher),
|
||||
trade_timer(),
|
||||
poll_period_ms(100),
|
||||
state(){
|
||||
}
|
||||
};
|
||||
|
||||
MarketDataAuxiliaryServiceServer::MarketDataAuxiliaryServiceServer(bts::api::ServiceContext& context)
|
||||
MarketDataAuxiliaryServiceServer::MarketDataAuxiliaryServiceServer(
|
||||
bts::api::ServiceContext& context)
|
||||
:
|
||||
MarketDataAuxiliaryServiceBase(context),
|
||||
me(new PImpl(context,
|
||||
make_volume_at_price_stateful_publisher())){
|
||||
|
||||
auto& threadpool = utils::Dispatcher::get_named("TradesQuery");
|
||||
me->trade_timer =
|
||||
std::make_unique<utils::DispatcherTimer>(threadpool,
|
||||
me->poll_period_ms,
|
||||
[this]() {
|
||||
me->relay_service.requestmd(me->state.md_req(),
|
||||
[this](const bts::api::Result<MDReply>& md_reply)
|
||||
{
|
||||
if(md_reply.result()!=nullptr)
|
||||
_scan_trades(*md_reply.result());}
|
||||
);
|
||||
});
|
||||
me->trade_timer->start();
|
||||
}
|
||||
|
||||
MarketDataAuxiliaryServiceServer::~MarketDataAuxiliaryServiceServer(){
|
||||
void MarketDataAuxiliaryServiceServer::_scan_trades(const MDReply& md_reply){
|
||||
uint32_t n_trades=0, total_unique_levels=0;
|
||||
bts::TimeStamp t0=bts::Timer::now();
|
||||
for(const auto& cr : md_reply.channels())
|
||||
me->state.on_new_trades(cr,
|
||||
me->publisher,
|
||||
n_trades,
|
||||
total_unique_levels);
|
||||
bts::TimeStamp t1=bts::Timer::now();
|
||||
double usecs=static_cast<double>(us_diff (t1,t0));
|
||||
LOG(OrderMan,Info,"MarketDataAuxiliaryServiceServer::_scan_trades "
|
||||
"trades:{} tot_unique:{} usecs:{}",
|
||||
n_trades,total_unique_levels,usecs);
|
||||
me->publisher.flush();
|
||||
}
|
||||
|
||||
MarketDataAuxiliaryServiceServer::~MarketDataAuxiliaryServiceServer(){
|
||||
}
|
||||
}}}
|
||||
@@ -7,14 +7,18 @@
|
||||
|
||||
namespace bts{
|
||||
namespace api {class ServiceContext;}
|
||||
namespace co2 {class MDReply;}
|
||||
namespace md{
|
||||
namespace auxiliary{
|
||||
|
||||
class MarketDataAuxiliaryServiceServer : public bts::api::md::auxiliary::MarketDataAuxiliaryServiceBase
|
||||
class MarketDataAuxiliaryServiceServer :
|
||||
public bts::api::md::auxiliary::MarketDataAuxiliaryServiceBase
|
||||
{
|
||||
private:
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
private:
|
||||
void _scan_trades(const bts::co2::MDReply&);
|
||||
public:
|
||||
MarketDataAuxiliaryServiceServer(bts::api::ServiceContext& context);
|
||||
~MarketDataAuxiliaryServiceServer();
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "VolumeAtPriceState.h"
|
||||
#include "lib/md/get_symbols.h"
|
||||
#include "lib/api/services/MarketDataRelay.pb.h"
|
||||
//#include "lib/api/services/MarketDataRelay.client.pb.h"
|
||||
|
||||
namespace bts{
|
||||
namespace md{
|
||||
namespace auxiliary{
|
||||
|
||||
using namespace bts::api::md::auxiliary;
|
||||
using namespace bts::co2;
|
||||
using namespace std;
|
||||
|
||||
VolumeAtPriceState::VolumeAtPriceState()
|
||||
:
|
||||
_channels(),
|
||||
_md_req(),
|
||||
_record_id(0){
|
||||
std::set<bts::md::UserSymbol> syms;
|
||||
bts::md::get_system_md_symbols(syms);
|
||||
for(const auto& s : syms){
|
||||
SecurityChannel c;
|
||||
c.set_flags(MDRequest::TRADE_LOG);
|
||||
c.set_type(s.type());
|
||||
c.set_exchange(s.exchange());
|
||||
c.set_symbol(s.symbol());
|
||||
c.set_trade_cursor(0);
|
||||
c.set_segment_id(0);
|
||||
_update_or_add(c);
|
||||
}
|
||||
}
|
||||
|
||||
ChannelVolume& VolumeAtPriceState::_update_or_add(const SecurityChannel& channel){
|
||||
for(auto& v : _channels)
|
||||
if(v.match_update(channel))
|
||||
return v;
|
||||
SecurityChannel* new_channel_ptr = _md_req.add_channels();
|
||||
new_channel_ptr->CopyFrom(channel);
|
||||
_channels.emplace_back(new_channel_ptr);
|
||||
return _channels.back();
|
||||
}
|
||||
|
||||
void VolumeAtPriceState::on_new_trades(const ChannelReply& reply,
|
||||
MarketDataAuxiliaryServiceBase::Volume_at_priceStatefulPublisher& publisher,
|
||||
uint32_t& n_trades,
|
||||
uint32_t& total_unique_levels){
|
||||
ChannelVolume& channel_vol=_update_or_add(reply.channel());
|
||||
for(const TradeMessage& t : reply.trade_log()){
|
||||
const VolumeAtPriceLevel& sec_level_vol=channel_vol.add_trade(t,
|
||||
_record_id);
|
||||
publisher.add_or_update(sec_level_vol);
|
||||
n_trades++;
|
||||
}
|
||||
total_unique_levels = _record_id;
|
||||
}
|
||||
|
||||
const bts::co2::MDRequest& VolumeAtPriceState::md_req() const{
|
||||
return _md_req;
|
||||
}
|
||||
}}}
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include "lib/api/services/MarketDataAuxiliaryService.server.pb.h"
|
||||
#include "lib/api/services/MarketDataRelay.pb.h"
|
||||
#include "ChannelVolume.h"
|
||||
|
||||
namespace bts{
|
||||
namespace co2 {class SecurityChannel;class ChannelReply;}
|
||||
namespace md{
|
||||
namespace auxiliary{
|
||||
|
||||
// this is the entire state for the volume at
|
||||
// price levels for all channels.
|
||||
|
||||
class VolumeAtPriceState{
|
||||
private:
|
||||
std::vector<ChannelVolume> _channels;
|
||||
bts::co2::MDRequest _md_req;
|
||||
int _record_id;
|
||||
private:
|
||||
// if the channel is present, its updated (trade_cursor etc)
|
||||
// else its created from the channel
|
||||
ChannelVolume& _update_or_add(const bts::co2::SecurityChannel& channel);
|
||||
public:
|
||||
VolumeAtPriceState ();
|
||||
//encorporates the reply, and publishes it
|
||||
void on_new_trades(const bts::co2::ChannelReply& channel,
|
||||
bts::api::md::auxiliary::MarketDataAuxiliaryServiceBase::Volume_at_priceStatefulPublisher& publisher,
|
||||
uint32_t& n_trades,
|
||||
uint32_t& total_unique_levels);
|
||||
const bts::co2::MDRequest& md_req() const;
|
||||
};
|
||||
}}}
|
||||
@@ -213,7 +213,7 @@ void md_tool(std::vector<std::string> const &args) {
|
||||
else if (cmd == "run") run_market_data_publishers_forever();
|
||||
else if (cmd == "relay") relay_everything();
|
||||
else if (cmd == "test_relay") relay_everything();
|
||||
else if (cmd == "dumpsecurity") dump_db(vector<string>(args.begin()+1, args.end()));
|
||||
else if (cmd == "dumpsecurity" || cmd == "dumpsecurities") dump_db(vector<string>(args.begin()+1, args.end()));
|
||||
else printhelp();
|
||||
}
|
||||
|
||||
|
||||
@@ -223,11 +223,10 @@ void AdminServiceServer::_cancel_orders(const vector<string>& accounts,
|
||||
user_map.find(ord.def().user()) != user_map.end())
|
||||
keys.push_back(ord.key());
|
||||
}
|
||||
auto cb = [&](bts::api::Result<::bts::api::orderman::Response>) -> void {};
|
||||
for(uint32_t k : keys){
|
||||
Cancel c;
|
||||
c.set_order_key(k);
|
||||
_order_service.cancel_order(c, cb);
|
||||
_order_service.cancel_order(c, [](const auto&){});
|
||||
}
|
||||
}
|
||||
void AdminServiceServer::_publish_md_entitlements(){
|
||||
|
||||
@@ -1 +1 @@
|
||||
set(sources ../../externals/linux/include/google/protobuf/descriptor.proto;../../externals/linux/include/google/protobuf/timestamp.proto;../lib/api/apicore.proto;../lib/api/apigateway.proto;../lib/api/apioptions.proto;../lib/api/services/AdminService.proto;../lib/api/services/ApiUnitTestService.proto;../lib/api/services/ErrorReportService.proto;../lib/api/services/HelloService.proto;../lib/api/services/MarketDataRelay.proto;../lib/api/services/OrderService.proto;../lib/api/services/OutOfProcessURLListener.proto;../lib/api/services/PersistenceService.proto;../lib/api/services/PositionService.proto;../lib/api/services/ShellDiagnosticService.proto;../lib/api/services/ShellLatencyService.proto;../lib/api/services/SyntheticSecurityService.proto;../lib/api/services/UserService.proto;../lib/domain_model/Security.proto;../lib/md/protos/co2.proto;../lib/sparkproto/SparkProtos.proto;api/build.sh;api/node_modules/cssstyle/scripts/run_tests.sh;api/node_modules/exit/test/fixtures/create-files.sh;api/node_modules/protobufjs/cli/node_modules/acorn-jsx/node_modules/acorn/bin/update_authors.sh;api/node_modules/watch/release.sh;api/quiet_build.sh;api/src/DynamicService.ts;api/src/ServiceContext.ts;api/src/bts_assert.ts;ui/src/Access.fs;ui/src/Accounts/ClipLimits.fs;ui/src/Accounts/ProductLimits.fs;ui/src/Accounts/SecurityLimits.fs;ui/src/Accounts/State.fs;ui/src/Accounts/Types.fs;ui/src/Accounts/View.fs;ui/src/App.fs;ui/src/Cmd.fs;ui/src/Controls/Button.fs;ui/src/Controls/DataGrid.fs;ui/src/Controls/Fields.fs;ui/src/Controls/Modal.fs;ui/src/Controls/ReactGrid.fs;ui/src/Controls/Table.fs;ui/src/Controls/nbsp.fs;ui/src/Global.fs;ui/src/Imports.fs;ui/src/Lens.fs;ui/src/Login/Login.fs;ui/src/Nav.fs;ui/src/State.fs;ui/src/Types.fs;ui/src/Users/State.fs;ui/src/Users/Types.fs;ui/src/Users/View.fs;ui/src/Util/EnumUtils.fs;ui/src/Util/JSMap.fs)
|
||||
set(sources ../../externals/linux/include/google/protobuf/descriptor.proto;../../externals/linux/include/google/protobuf/timestamp.proto;../lib/api/apicore.proto;../lib/api/apigateway.proto;../lib/api/apioptions.proto;../lib/api/services/AdminService.proto;../lib/api/services/ApiUnitTestService.proto;../lib/api/services/ErrorReportService.proto;../lib/api/services/HelloService.proto;../lib/api/services/MarketDataAuxiliaryService.proto;../lib/api/services/MarketDataRelay.proto;../lib/api/services/OrderService.proto;../lib/api/services/OutOfProcessURLListener.proto;../lib/api/services/PersistenceService.proto;../lib/api/services/PositionService.proto;../lib/api/services/ShellDiagnosticService.proto;../lib/api/services/ShellLatencyService.proto;../lib/api/services/SyntheticSecurityService.proto;../lib/api/services/UserService.proto;../lib/domain_model/Security.proto;../lib/md/protos/co2.proto;../lib/sparkproto/SparkProtos.proto;api/build.sh;api/node_modules/cssstyle/scripts/run_tests.sh;api/node_modules/exit/test/fixtures/create-files.sh;api/node_modules/protobufjs/cli/node_modules/acorn-jsx/node_modules/acorn/bin/update_authors.sh;api/node_modules/watch/release.sh;api/quiet_build.sh;api/src/DynamicService.ts;api/src/ServiceContext.ts;api/src/bts_assert.ts;ui/src/Access.fs;ui/src/Accounts/ClipLimits.fs;ui/src/Accounts/ProductLimits.fs;ui/src/Accounts/SecurityLimits.fs;ui/src/Accounts/State.fs;ui/src/Accounts/Types.fs;ui/src/Accounts/View.fs;ui/src/App.fs;ui/src/Cmd.fs;ui/src/Controls/Button.fs;ui/src/Controls/DataGrid.fs;ui/src/Controls/Fields.fs;ui/src/Controls/Modal.fs;ui/src/Controls/ReactGrid.fs;ui/src/Controls/Table.fs;ui/src/Controls/nbsp.fs;ui/src/Global.fs;ui/src/Imports.fs;ui/src/Lens.fs;ui/src/Login/Login.fs;ui/src/Nav.fs;ui/src/State.fs;ui/src/Types.fs;ui/src/Users/State.fs;ui/src/Users/Types.fs;ui/src/Users/View.fs;ui/src/Util/EnumUtils.fs;ui/src/Util/JSMap.fs)
|
||||
@@ -1,20 +0,0 @@
|
||||
#/bin/bash
|
||||
DIR=$(dirname ${BASH_SOURCE[0]})
|
||||
TARGET=${1:-gcc_debug}
|
||||
echo TARGET=$TARGET
|
||||
MAKEDIR=$DIR/../build/$TARGET/
|
||||
if [ ! -f $MAKEDIR/Makefile ]; then
|
||||
$DIR/setup_builds.sh
|
||||
fi
|
||||
cd $MAKEDIR
|
||||
time make -j`nproc`
|
||||
if (($? >0)); then
|
||||
echo "Build failed..."
|
||||
exit 1
|
||||
fi
|
||||
# start config
|
||||
(cd ~/www/ && python -m SimpleHTTPServer > /dev/null 2>/dev/null) &
|
||||
# and ssh for diagnostics
|
||||
/usr/sbin/sshd
|
||||
# and sparkd
|
||||
./src/server/sparkd/sparkd run
|
||||
@@ -1,15 +1,3 @@
|
||||
# This should mirror the one found in Security.proto
|
||||
$cme_mics = @{
|
||||
"CME" = 1
|
||||
"NYMEX" = 2
|
||||
"CBT" = 3
|
||||
"COMEX" = 4
|
||||
"MGE" = 5
|
||||
"DME" = 6
|
||||
"NYMSW" = 7
|
||||
"FXS" = 8
|
||||
}
|
||||
|
||||
$known_good = @{
|
||||
"IC" = 50
|
||||
"IH" = 50
|
||||
|
||||
@@ -39,7 +39,7 @@ $b | % {
|
||||
# mics
|
||||
"CmeSymbolMics`n{`n`tvalue`n`t{" | out-file -Encoding ascii $output_file -Append
|
||||
$mic_grouping | % {
|
||||
"`t`tcme_mic {{ key: `"{0}`" value: {1} }}" -f $_.Group[0].Sym, $cme_mics[$_.Group[0].Exch] } `
|
||||
"`t`tcme_mic {{ key: `"{0}`" value: {1} }}" -f $_.Group[0].Sym, $_.Group[0].Exch } `
|
||||
| out-file -Encoding ascii $output_file -Append
|
||||
"`t}`n}" | out-file -Encoding ascii $output_file -Append
|
||||
|
||||
|
||||
Reference in new issue
Block a user