Compare commits

...
16 Commits
Author SHA1 Message Date
John Colvin 3b320a1075 MDConsumerHandle - don't convert LLDateTimes to System.DateTimes 2018-09-17 12:55:54 -04:00
John Colvin e838413541 minor refactoring in DispatcherUpdateMaster 2018-09-17 11:42:17 -04:00
John Colvin 7d6d72b423 mview - perform update work in parallel with new DispatcherUpdateMaster 2018-09-16 17:17:43 -04:00
John Colvin 891d674ca4 overload MDConsumerHandle.get_last_trade to avoid creating unused timestamp via ll_to_parts 2018-09-16 14:54:32 -04:00
Taha Afzal 92c1508b8c Put the VolumeAtPrice behind a toggle config 2018-09-14 14:58:35 -04:00
Jake Norbut 466915f6e9 Updating MICS conf to use unquoted enum string rather than enum value 2018-09-14 13:57:37 -05:00
Pedro Pinto 1c68cfa08e Fixed clang warning. 2018-09-13 20:44:28 +00:00
Pedro Pinto cc75872c04 Fixed crashing bug in order plugin. 2018-09-13 20:28:48 +00:00
Pedro Pinto 7e93866596 Tweaks to metrics tools. 2018-09-13 20:28:48 +00:00
Taha Afzal f4213eefe9 fixing header inclusions 2018-09-13 16:26:06 -04:00
Taha Afzal 72bfafb376 Merge branch 'master' of bitbucket.org:bluetradesys/spark 2018-09-13 15:24:58 -04:00
Taha Afzal 5dbacfddd5 SPARK-1672(Volume at price) 2018-09-13 15:24:49 -04:00
Pedro Pinto e29ea5d89b SPARK-1514, Server side SDK code complete. 2018-09-12 18:43:17 +00:00
Eric Harding 2885d929a8 Safe me from my own mistyping 2018-09-11 15:19:10 -04:00
Eric Harding a3e5bc4fba Prune unused script from tools 2018-09-11 12:50:20 -04:00
Taha Afzal bb19f737d5 SPARK-1672 hooked up the timer for polling 2018-09-10 22:28:48 -04:00
73 changed files with 2851 additions and 5243 deletions

No files matched your search

+1
View File
@@ -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/
+2
View File
@@ -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);
}
}
+13 -7
View File
@@ -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>();
+2 -1
View File
@@ -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 {
+10 -5
View File
@@ -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; } }
+12 -7
View File
@@ -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
View File
@@ -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];
+79 -3
View File
@@ -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
+4
View File
@@ -26,4 +26,8 @@ message OrdersSoftCleanup{
message ToastNotifications {
optional bool enabled = 1 [default = false];
}
message VolumeAtPrice{
optional bool enabled = 1 [default = true];
}
+1
View File
@@ -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"] =
+1
View File
@@ -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;
+3 -3
View File
@@ -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()
+2 -1
View File
@@ -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;
+21 -22
View File
@@ -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
+37 -29
View File
@@ -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;
};
}}
+45 -32
View File
@@ -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 &registry)
: 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,
+16 -30
View File
@@ -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
-2
View File
@@ -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
@@ -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()]
+27 -7
View File
@@ -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
+32 -24
View File
@@ -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
+26
View File
@@ -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
+28
View File
@@ -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
+50
View File
@@ -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
+7
View File
@@ -0,0 +1,7 @@
#pragma once
namespace bts {
class SparkServices;
namespace plugin {
void init_plugins(SparkServices &);
}}
+3 -2
View File
@@ -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)
-13
View File
@@ -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
+24
View File
@@ -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.
+385
View File
@@ -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
View File
@@ -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)
-18
View File
@@ -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
View File
@@ -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)
+16 -1
View File
@@ -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());
+50
View File
@@ -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;
}
}}}
+28
View File
@@ -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;
}
}}}
+32
View File
@@ -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;
};
}}}
+1 -1
View File
@@ -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
View File
@@ -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)
-20
View File
@@ -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
-12
View File
@@ -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
+1 -1
View File
@@ -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