Compare commits

...
30 Commits
Author SHA1 Message Date
Jake Norbut 4e9a7d576e Merge branch 'qa' into prod 2018-07-23 19:03:39 -05:00
Jake Norbut 5e056dfff4 pnl - account for current time in calculating start of day time 2018-07-23 17:18:22 -05:00
Jake Norbut 4029ccf8e6 pnl - using actual mid and not a tick-rounded one 2018-07-23 16:06:49 -05:00
Pedro Pinto 22911d582b Merge branch 'qa' of bitbucket.org:bluetradesys/spark into qa 2018-07-23 20:35:30 +00:00
Pedro Pinto 6ef7a2ccb5 More release_notes 2018-07-23 20:32:40 +00:00
Jake Norbut 737a07cecb added notes 2018-07-23 14:57:45 -05:00
Eric Harding 1cbea3d1ee SPARK-1467 Favorites misbehaving 2018-07-23 15:47:12 -04:00
Pedro Pinto 4dbedfa1f7 Added ops_notes.txt 2018-07-23 19:41:09 +00:00
Pedro Pinto 074f87dd37 Release notes 2018-07-23 15:38:16 -04:00
Pedro Pinto 6ee0ca9589 Tweaked release_notes.txt 2018-07-23 14:48:33 -04:00
Michael Harding 5745c13355 Sim Order Routing 2018-07-23 11:22:51 -04:00
Kevin Darby 5f99edde0e small typo in test, 0.005 vs 0.05 2018-07-20 17:45:50 -04:00
Pedro Pinto d39bc5c73c Merge branch 'qa' of bitbucket.org:bluetradesys/spark into qa 2018-07-20 21:40:50 +00:00
Pedro Pinto 9cb6d5ab88 Fixed up tests to reflect lack of wild cards in Admin UI. 2018-07-20 21:40:44 +00:00
Pedro Pinto 278432a35b Fixed bootstraping of admin data to avoid wild cards everywhere. 2018-07-20 21:37:23 +00:00
Kevin Darby 13c414f301 fix small typo in Taha's test 2018-07-20 17:33:39 -04:00
Eric Harding 34f5265a42 Update test instructions 2018-07-20 17:13:37 -04:00
Pedro Pinto 83103e6dc4 Merge branch 'qa' of bitbucket.org:bluetradesys/spark into qa 2018-07-20 12:54:09 -04:00
Pedro Pinto add631b04d Fixed test configuration. 2018-07-20 12:53:56 -04:00
Pedro Pinto e08dc5dfba Add back the option to run sim without replay. 2018-07-20 12:53:34 -04:00
John Colvin 6a8e995c9c SPARK-1452 Synth grid is not filterable by sec key 2018-07-20 11:41:19 -04:00
John Colvin d7c460ac98 SPARK-1440 Creating > 2 legs from MD View 2018-07-20 11:22:20 -04:00
Eric Harding 7871dc5e4f Update 2 tests' instructions 2018-07-19 21:48:52 -04:00
Eric Harding 1aab1db4ca Update cmakedeps 2018-07-19 21:48:44 -04:00
John Colvin 373187c091 SPARK-1464 Couple of small things in the trigger UI 2018-07-19 18:35:06 -04:00
Jake Norbut 423d127ee9 Updating order book order to test new Recreate funcionality 2018-07-19 17:08:43 -05:00
Jake Norbut 14f306d50d SPARK-1471 Adding FillKind to PnL; also will always pass 0 as the time to md query 2018-07-19 16:38:49 -05:00
Eric Harding 71fe863f1b Add server_info http endpoint to serve http://versions 2018-07-19 15:12:39 -04:00
Pedro Pinto ac47f0246f Merge branch 'master' into qa 2018-07-19 18:41:34 +00:00
Kevin Darby 8cef60b5ab top test case, might not have pushed in time 2018-06-18 10:20:44 -04:00
48 changed files with 423 additions and 264 deletions

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
1.1.0
- With this release we dropped wild cards from limits, so any user
that has limits expressed in terms of wild cards will have to have
those re-entered explicitly
- With this release we add per user location and smp id tags. At least
the location will have to be set through the admin UI for every user
+9 -4
View File
@@ -1,5 +1,10 @@
1.1.0
Added self match protection, location and self match protection
instructions tags, these will have to be set in the UI for the user
for orders to be entered.
- Added per user self match protection, location and self match protection FIX tag settings
- Implemented a new "Trigger Order" algo
- Corrected tick formatting for a number of products
- Added the hability to recreate canceled orders
- Added leg fills to facilitate futured based PnL
- PnL report now has PnL columns calculated based on your start of day, current day, and total position
- Start, Day and Total PnL columns are painted with a red or green background color based on if the pnl value is negative or positive respectively
- Corrected cash per point values, used in pnl calculations, for a number of products
- PnL report will now remember any customizations you make to filtering and/or sorting criteria
@@ -55,7 +55,7 @@ namespace mbts.spark {
})
),
SparkCommands.ShowTimeAndSales.complete(_vm.selected_securities_observable(), _ => true, secs => secs.Count > 0 ? new SecurityCriteria(secs) : _state.security_criteria),
SparkCommands.ShowSyntheticCreate.complete(_vm.selected_securities_observable(), secs => secs.Count > 0 && secs.Count < 3, secs => new SecurityCriteria(secs))
SparkCommands.ShowSyntheticCreate.complete(_vm.selected_securities_observable(), secs => secs.Count > 0 && secs.Count <= 24, secs => new SecurityCriteria(secs))
};
_subscriptions = _bus.subscribe(update_securities_tag).OnDispatcher().Subscribe(c =>
_state_changed?.Invoke(_state = new MarketViewWindowFactory.StartupData(c, _vm.rows_view.GetSortingCriteria(), _vm.get_filter_states())));
@@ -67,4 +67,4 @@ namespace mbts.spark {
Commands.OfType<IDisposable>().DisposeAll();
}
}
}
}
@@ -72,9 +72,9 @@
c:DataGridFilterProperties.Filter="{Binding DataContext.security_key_filter, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterActive="{Binding DataContext.security_key_filter.active, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterOpen="{Binding DataContext.security_key_filter.open, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterTemplate="{StaticResource IntMinMaxTemplate}"
c:DataGridFilterProperties.FilterTemplate="{StaticResource RegexTemplate}"
/>
</DataGrid.Columns>
</c:DataGridEx>
</Grid>
</UserControl>
</UserControl>
@@ -53,6 +53,8 @@ namespace bts.shell {
public IntMinMaxState n_legs;
[ProtoMember(5)]
public UIntMinMaxState n_working_orders;
[ProtoMember(6)]
public string security_key;
}
}
}
}
@@ -26,8 +26,9 @@ namespace mbts.spark {
description_filter.load_state(filters.description);
n_legs_filter.load_state(filters.n_legs);
n_working_orders_filter.load_state(filters.n_working_orders);
security_key_filter.load_state(filters.security_key);
}
_dispose = DataGridFilterHelper.hook_filters(rows_view, create_time_filter, name_filter, description_filter, n_legs_filter, n_working_orders_filter);
_dispose = DataGridFilterHelper.hook_filters(rows_view, create_time_filter, name_filter, description_filter, n_legs_filter, n_working_orders_filter, security_key_filter);
}
protected override Row row_factory((ExecutionStrategyImmutable? strategy, SecurityMD md) row_model) =>
@@ -41,6 +42,7 @@ namespace mbts.spark {
public IDataGridColumnPersistentFilter<Row, string> description_filter { get; } = new RegexFilterVM<Row>(r => r.description, nameof(Row.description));
public IDataGridColumnPersistentFilter<Row, IntMinMaxState> n_legs_filter { get; } = new IntMinMax<Row>(r => r.n_legs, nameof(Row.n_legs));
public IDataGridColumnPersistentFilter<Row, UIntMinMaxState> n_working_orders_filter { get; } = new UIntMinMax<Row>(r => r.n_working_orders, nameof(Row.n_legs));
public IDataGridColumnPersistentFilter<Row, string> security_key_filter { get; } = new RegexFilterVM<Row>(r => r.security_key.ToString(), nameof(Row.security_key));
public FilterStates get_filter_states() =>
new FilterStates {
@@ -48,7 +50,8 @@ namespace mbts.spark {
create_time = create_time_filter.get_state(),
name = name_filter.get_state(),
n_legs = n_legs_filter.get_state(),
n_working_orders = n_working_orders_filter.get_state()
n_working_orders = n_working_orders_filter.get_state(),
security_key = security_key_filter.get_state()
};
#endregion
@@ -104,4 +107,4 @@ namespace mbts.spark {
});
}
}
}
}
@@ -1,4 +1,5 @@
using bts.api;
using bts.api.orderman;
using bts.spark;
using mbts.spark;
using mbts.spark.filters;
@@ -83,8 +84,8 @@ namespace bts.shell {
public DoubleMinMaxState total_pnl;
[ProtoMember(12)]
public DoubleMinMaxState pnl_price;
[ProtoMember(13)]
public Fill.Types.FillKind[] fill_kind;
}
}
@@ -21,10 +21,9 @@ namespace mbts.spark {
public ExistingOrderTicketVM(OrdersModel model, IObservable<OrderRecordTuple> order_source, IObservable<int[]> calculator_buttons) {
uint? key = null;
var security_md_source = order_source.Where(ot => ot.security_md.HasValue).Select(ot => ot.security_md.Value);
var security_source = security_md_source.Select(smd => smd.security);
//
_security = backing(nameof(security), security_source, SecurityDataHelper.Defaults.SecurityImmutable);
properties_vm = new OrderPropertiesEditorVM(model, security_source.OnDispatcher(), order_source.Select(ot => new InlineOrderProperties(model, ot.order.Def)));
_security = backing(nameof(security), security_md_source.Select(smd => smd.security), SecurityDataHelper.Defaults.SecurityImmutable);
properties_vm = new OrderPropertiesEditorVM(model, security_md_source, order_source.Select(ot => new InlineOrderProperties(model, ot.order.Def)));
_price = backing(nameof(price), double.NaN);
size_calculator = new CalculatorLogic(null, calculator_buttons);
_current_price = backing(nameof(current_price), order_source.Select(ort => ort.order.State.Price));
+2 -3
View File
@@ -47,9 +47,8 @@ namespace mbts.spark {
IObservable<InlineOrderTicketProperties> props_source,
IObservable<int[]> calculator_buttons
) {
var security_source = security_md_source.Select(smd => smd.security);
_security = backing(nameof(security), security_source, SecurityDataHelper.Defaults.SecurityImmutable);
properties_vm = new OrderPropertiesEditorVM(model, security_source, props_source.Select(p => p.order_props));
_security = backing(nameof(security), security_md_source.Select(smd => smd.security), SecurityDataHelper.Defaults.SecurityImmutable);
properties_vm = new OrderPropertiesEditorVM(model, security_md_source, props_source.Select(p => p.order_props));
bbo = new BBOVM(security_md_source);
send_order = new DelegateCommand<Side>(side => {
bool price_valid = _validate_price(), size_valid = size_calculator.validate();
@@ -8,7 +8,6 @@ using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
namespace mbts.spark {
class InlineOrderProperties {
@@ -44,8 +43,9 @@ namespace mbts.spark {
readonly SelectorProperty<IOrderTypeVM> _order_type;
IDisposable _order_type_param_errors_sub;
public OrderPropertiesEditorVM(OrdersModel model, IObservable<SecurityImmutable> security_source, IObservable<InlineOrderProperties> order_properties) {
public OrderPropertiesEditorVM(OrdersModel model, IObservable<SecurityMD> security_md_source, IObservable<InlineOrderProperties> order_properties) {
_model = model;
var security_source = security_md_source.Select(smd => smd.security);
_security = backing(nameof(security), security_source.OnDispatcher(), SecurityDataHelper.Defaults.SecurityImmutable);
// guarentee that "this.security" will always be set before observers are notified
// this is important bc some observers will reference "this.security" in their callbacks
@@ -75,7 +75,7 @@ namespace mbts.spark {
_dispose = Disposable.Create(() => _order_type.Changed -= on_selected_order_type_changed);
// local methods
IOrderTypeVM create_order_type_vm(CustomOrderDefinitionImmutable cd) {
var vm = OrderTypeVMFactory.create(cd.CustomCase, model, security_source);
var vm = OrderTypeVMFactory.create(cd.CustomCase, model, security_md_source);
vm.load_from(cd);
return vm;
}
@@ -136,6 +136,7 @@ namespace mbts.spark {
protected override void Dispose(bool disposing) {
base.Dispose(disposing);
Disposable.dispose(ref _order_type_param_errors_sub);
_order_type.items.OfType<IDisposable>().DisposeAll();
}
}
}
@@ -26,7 +26,7 @@ namespace mbts.spark {
}
class IcebergOrderVM : OrderTypeVMBase<IcebergOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable {
readonly IObservable<SecurityImmutable> _security_source;
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
@@ -34,18 +34,18 @@ namespace mbts.spark {
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
public IcebergOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source)
: this(model, security_source, security_source.Select(s =>
new InlineIcebergOrderProperties(model.factory.default_order_type(s), model.factory.default_order_types(s).ToList()))) { }
public IcebergOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineIcebergOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
public IcebergOrderVM(OrdersModel model,
IObservable<SecurityImmutable> security_source,
IObservable<SecurityMD> security_md_source,
IObservable<InlineIcebergOrderProperties> inline_properties)
: base(model) {
_security_source = security_source;
_security_md_source = security_md_source;
_dispose = Disposable.Create(
security_source.OnDispatcher()
.Subscribe(s => _security = s),
security_md_source.OnDispatcher()
.Subscribe(smd => _security = smd.security),
inline_properties.OnDispatcher()
.Subscribe(p => {
if (_order_types.Count == 0 || p.child_order_types.force_override) {
@@ -68,7 +68,7 @@ namespace mbts.spark {
public ICollection<IOrderTypeVM> child_order_types {
get {
if (_child_order_choices == null) {
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
}
return _child_order_choices;
}
@@ -53,7 +53,7 @@ namespace mbts.spark
class JoinOrderVM : OrderTypeVMBase<JoinOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable
{
readonly IObservable<SecurityImmutable> _security_source;
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
@@ -79,17 +79,17 @@ namespace mbts.spark
}
public int hedge_ticks { get; set; } = 1;
public JoinOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source)
: this(model, security_source, security_source.Select(s =>
new InlineJoinOrderProperties(model.factory.default_order_type(s), model.factory.default_order_types(s).ToList()))) { }
public JoinOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineJoinOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
public JoinOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source,
public JoinOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineJoinOrderProperties> inline_properties) : base(model)
{
_security_source = security_source;
_security_md_source = security_md_source;
_dispose = Disposable.Create(
security_source.OnDispatcher()
.Subscribe(s => _security = s),
security_md_source.OnDispatcher()
.Subscribe(smd => _security = smd.security),
inline_properties.OnDispatcher()
.Subscribe(p => {
if (_order_types.Count == 0 || p.child_order_types.force_override)
@@ -157,7 +157,7 @@ namespace mbts.spark
get
{
if (_child_order_choices == null)
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
return _child_order_choices;
}
}
@@ -167,7 +167,7 @@ namespace mbts.spark
get
{
if (_hedge_order_choices == null)
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_source));
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
return _hedge_order_choices;
}
}
@@ -35,7 +35,7 @@ namespace mbts.spark
class LeanOrderVM : OrderTypeVMBase<LeanOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable
{
readonly IObservable<SecurityImmutable> _security_source;
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
@@ -46,17 +46,17 @@ namespace mbts.spark
public bts.spark.QuantityMeasure cross_threshold { get; set; } = new bts.spark.QuantityMeasure() { Ratio = 1.0, Absolute = 1 };
public uint max_chase_ticks { get; set; } = 10;
public LeanOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source)
: this(model, security_source, security_source.Select(s =>
new InlineLeanOrderProperties(model.factory.default_order_type(s), model.factory.default_order_types(s).ToList()))) { }
public LeanOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineLeanOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
public LeanOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source,
public LeanOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineLeanOrderProperties> inline_properties) : base(model)
{
_security_source = security_source;
_security_md_source = security_md_source;
_dispose = Disposable.Create(
security_source.OnDispatcher()
.Subscribe(s => _security = s),
security_md_source.OnDispatcher()
.Subscribe(smd => _security = smd.security),
inline_properties.OnDispatcher()
.Subscribe(p => {
if (_order_types.Count == 0 || p.child_order_types.force_override)
@@ -104,7 +104,7 @@ namespace mbts.spark
get
{
if (_child_order_choices == null)
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
return _child_order_choices;
}
}
@@ -4,6 +4,7 @@ using bts.spark;
using mbts.spark.utilities;
using mbts.ui.shell;
using System;
using System.Reactive.Linq;
using System.Windows.Input;
using static bts.api.orderman.CustomOrderDefinition;
@@ -12,33 +13,30 @@ namespace mbts.spark {
public static IOrderTypeVM market(OrdersModel model) => new MarketOrderVM(model);
public static IOrderTypeVM limit(OrdersModel model) => new LimitOrderVM(model);
public static IOrderTypeVM stop(OrdersModel model) => new StopOrderVM(model);
public static IOrderTypeVM stop_limit(OrdersModel model) => new StopLimitOrderVM(model);
public static IOrderTypeVM time_box(OrdersModel model, IObservable<SecurityImmutable> security_source) => new TimeBoxOrderVM(model, security_source);
public static IOrderTypeVM tick(OrdersModel model, IObservable<SecurityImmutable> security_source) => new TickOrderVM(model, security_source);
public static IOrderTypeVM lean(OrdersModel model, IObservable<SecurityImmutable> security_source) => new LeanOrderVM(model, security_source);
public static IOrderTypeVM join(OrdersModel model, IObservable<SecurityImmutable> security_source) => new JoinOrderVM(model, security_source);
public static IOrderTypeVM top(OrdersModel model, IObservable<SecurityImmutable> security_source) => new TopOrderVM(model, security_source);
public static IOrderTypeVM trigger(OrdersModel model, IObservable<SecurityImmutable> security_source) => new TriggerOrderVM(model, security_source);
public static IOrderTypeVM iceberg(OrdersModel model, IObservable<SecurityImmutable> security_source) => new IcebergOrderVM(model, security_source);
public static IOrderTypeVM stop_limit(OrdersModel model, IObservable<SecurityMD> security_md_source) => new StopLimitOrderVM(model, security_md_source);
public static IOrderTypeVM time_box(OrdersModel model, IObservable<SecurityMD> security_md_source) => new TimeBoxOrderVM(model, security_md_source);
public static IOrderTypeVM tick(OrdersModel model, IObservable<SecurityMD> security_md_source) => new TickOrderVM(model, security_md_source);
public static IOrderTypeVM lean(OrdersModel model, IObservable<SecurityMD> security_md_source) => new LeanOrderVM(model, security_md_source);
public static IOrderTypeVM join(OrdersModel model, IObservable<SecurityMD> security_md_source) => new JoinOrderVM(model, security_md_source);
public static IOrderTypeVM top(OrdersModel model, IObservable<SecurityMD> security_md_source) => new TopOrderVM(model, security_md_source);
public static IOrderTypeVM trigger(OrdersModel model, IObservable<SecurityMD> security_md_source) => new TriggerOrderVM(model, security_md_source);
public static IOrderTypeVM iceberg(OrdersModel model, IObservable<SecurityMD> security_md_source) => new IcebergOrderVM(model, security_md_source);
public static IOrderTypeVM spreader(OrdersModel model, IObservable<SecurityImmutable> security_source) => new SpreaderOrderVM(model, security_source);
static Func<CustomOneofCase, IOrderTypeVM> _get_factory(OrdersModel orders_model, IObservable<SecurityImmutable> security_source) =>
new Func<CustomOneofCase, IOrderTypeVM>(ot => create(ot, orders_model, security_source));
public static IOrderTypeVM create(CustomOneofCase order_type, OrdersModel model, IObservable<SecurityImmutable> security_source) {
public static IOrderTypeVM create(CustomOneofCase order_type, OrdersModel model, IObservable<SecurityMD> security_md_source) {
switch (order_type) {
case CustomOneofCase.Market: return market(model);
case CustomOneofCase.Limit: return limit(model);
case CustomOneofCase.Stop: return stop(model);
case CustomOneofCase.StopLimit: return stop_limit(model);
case CustomOneofCase.TimeBox: return time_box(model, security_source);
case CustomOneofCase.Tick: return tick(model, security_source);
case CustomOneofCase.Lean: return lean(model, security_source);
case CustomOneofCase.Join: return join(model, security_source);
case CustomOneofCase.Top: return top(model, security_source);
case CustomOneofCase.Trigger: return trigger(model, security_source);
case CustomOneofCase.Iceberg: return iceberg(model, security_source);
case CustomOneofCase.Spreader: return spreader(model, security_source);
case CustomOneofCase.StopLimit: return stop_limit(model, security_md_source);
case CustomOneofCase.TimeBox: return time_box(model, security_md_source);
case CustomOneofCase.Tick: return tick(model, security_md_source);
case CustomOneofCase.Lean: return lean(model, security_md_source);
case CustomOneofCase.Join: return join(model, security_md_source);
case CustomOneofCase.Top: return top(model, security_md_source);
case CustomOneofCase.Trigger: return trigger(model, security_md_source);
case CustomOneofCase.Iceberg: return iceberg(model, security_md_source);
case CustomOneofCase.Spreader: return spreader(model, security_md_source.Select(smd => smd.security));
default: throw new NotImplementedException();
}
}
@@ -1,18 +1,61 @@
using bts.api;
using bts.api.orderman;
using mbts.spark.utilities;
using mbts.utils;
using mbts.co2;
using mbts.ui;
using System;
using System.Reactive.Linq;
namespace mbts.spark {
static partial class OrderTypeVMFactory {
private class StopLimitOrderVM : OrderTypeVMBase<StopLimitOrderDefinition> {
double _stop_price = 0;
class InlineStopLimitOrderProperties {
readonly Func<InlineUserProperty<double>> _get_stop_price;
internal StopLimitOrderVM(OrdersModel model) : base(model) { }
public static IObservable<InlineStopLimitOrderProperties> subscribe(IObservable<SecurityMD> security_md_source) {
ulong time = 0;
return security_md_source.Select(smd => new InlineStopLimitOrderProperties(() => {
smd.md.get_bbo(ref time, out NativePriceSize bid, out NativePriceSize ask);
return new InlineUserProperty<double>(bid.price);
}));
}
public InlineStopLimitOrderProperties(Func<InlineUserProperty<double>> get_stop_price) =>
_get_stop_price = get_stop_price;
public InlineUserProperty<double> stop_price => _get_stop_price();
}
private class StopLimitOrderVM : OrderTypeVMBase<StopLimitOrderDefinition>, IDisposable {
UserProperty<double> _stop_price;
InlineStopLimitOrderProperties _inline_props;
IDisposable _dispose;
internal StopLimitOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source.Select(smd => smd.security.spec_or_default()), InlineStopLimitOrderProperties.subscribe(security_md_source)) { }
internal StopLimitOrderVM(OrdersModel model, IObservable<ContractSpecificationImmutable> spec_source, IObservable<InlineStopLimitOrderProperties> inline_properties) : base(model) {
_stop_price = new UserProperty<double>(backing(nameof(stop_price), double.NaN));
_dispose = Disposable.Create(
spec_source.OnDispatcher().Subscribe(s => {
spec = s;
RaisePropertyChanged(nameof(spec));
}), inline_properties.OnDispatcher().Subscribe(p => _inline_props = p));
}
public override bool editable_properties_open {
get => base.editable_properties_open;
set {
if (value) {
if (_update_inline_props())
_validate();
}
base.editable_properties_open = value;
}
}
public double stop_price {
get => _stop_price;
get => _stop_price.Value;
set {
_stop_price = value;
_stop_price.Value = value;
_validate();
}
}
@@ -21,6 +64,8 @@ namespace mbts.spark {
SecurityDataHelper.Defaults.ContractSpecificationImmutable;
public override void assign_to(CustomOrderDefinition value) {
_update_inline_props();
_validate();
if (!HasErrors) {
var sl = factory.stop_limit_order();
sl.StopPrice = stop_price;
@@ -28,9 +73,22 @@ namespace mbts.spark {
}
}
public void Dispose() => Disposable.dispose(ref _dispose);
// no need to constantly poll the md, just check the inline props when the popup opens, and right before sending an order
// (if the user never looks at the popup, assume that the bid_price will be used)
// TODO: add settings so the trigger-price can default to something relative to the md, e.g "bid-price" or "ask-price - nticks" or "best-bid-price with a minimum size of 10"
bool _update_inline_props() {
var inline_stop_price = _inline_props.stop_price;
if (inline_stop_price.has_value && (inline_stop_price.force_override || !_stop_price.setter_called)) {
_stop_price.bypass_setter(inline_stop_price.value);
return true;
} else return false;
}
void _validate() {
using (validation())
validation_assert(!DoubleHelper.IsNaNOrInfinity(_stop_price), string.Empty, nameof(stop_price));
validation_assert(!DoubleHelper.IsNaNOrInfinity(stop_price), string.Empty, nameof(stop_price));
}
}
}
@@ -41,7 +41,7 @@ namespace mbts.spark
class TickOrderVM : OrderTypeVMBase<TickOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable
{
readonly IObservable<SecurityImmutable> _security_source;
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
@@ -55,17 +55,17 @@ namespace mbts.spark
public uint max_chase_ticks { get; set; } = 10;
public bool detach_on_toward { get; set; } = true;
public TickOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source)
: this(model, security_source, security_source.Select(s =>
new InlineTickOrderProperties(model.factory.default_order_type(s), model.factory.default_order_types(s).ToList()))) { }
public TickOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineTickOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
public TickOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source,
public TickOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineTickOrderProperties> inline_properties) : base(model)
{
_security_source = security_source;
_security_md_source = security_md_source;
_dispose = Disposable.Create(
security_source.OnDispatcher()
.Subscribe(s => _security = s),
security_md_source.OnDispatcher()
.Subscribe(smd => _security = smd.security),
inline_properties.OnDispatcher()
.Subscribe(p => {
if (_order_types.Count == 0 || p.child_order_types.force_override)
@@ -131,7 +131,7 @@ namespace mbts.spark
get
{
if (_child_order_choices == null)
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
return _child_order_choices;
}
}
@@ -28,7 +28,7 @@ namespace mbts.spark {
class TimeBoxOrderVM : OrderTypeVMBase<TimeBoxOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable {
const double _start_immediately_delay_ms = 500;
readonly IObservable<SecurityImmutable> _security_source;
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
@@ -40,18 +40,18 @@ namespace mbts.spark {
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
public TimeBoxOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source)
: this(model, security_source, security_source.Select(s =>
new InlineTimeBoxOrderProperties(model.factory.default_order_type(s), model.factory.default_order_types(s).ToList()))) { }
public TimeBoxOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineTimeBoxOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
public TimeBoxOrderVM(OrdersModel model,
IObservable<SecurityImmutable> security_source,
IObservable<SecurityMD> security_md_source,
IObservable<InlineTimeBoxOrderProperties> inline_properties)
: base(model) {
_security_source = security_source;
_security_md_source = security_md_source;
_dispose = Disposable.Create(
security_source.OnDispatcher()
.Subscribe(s => _security = s),
security_md_source.OnDispatcher()
.Subscribe(smd => _security = smd.security),
inline_properties.OnDispatcher()
.Subscribe(p => {
if (_order_types.Count == 0 || p.child_order_types.force_override) {
@@ -94,7 +94,7 @@ namespace mbts.spark {
public ICollection<IOrderTypeVM> child_order_types {
get {
if (_child_order_choices == null) {
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
}
return _child_order_choices;
}
@@ -51,7 +51,7 @@ namespace mbts.spark
class TopOrderVM : OrderTypeVMBase<TopOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable
{
readonly IObservable<SecurityImmutable> _security_source;
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
@@ -77,18 +77,18 @@ namespace mbts.spark
}
public int hedge_ticks { get; set; } = 1;
public TopOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source)
: this(model, security_source, security_source.Select(s =>
new InlineTopOrderProperties(model.factory.default_order_type(s), model.factory.default_order_types(s).ToList())))
public TopOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineTopOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList())))
{ }
public TopOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source,
public TopOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineTopOrderProperties> inline_properties) : base(model)
{
_security_source = security_source;
_security_md_source = security_md_source;
_dispose = Disposable.Create(
security_source.OnDispatcher()
.Subscribe(s => _security = s),
security_md_source.OnDispatcher()
.Subscribe(smd => _security = smd.security),
inline_properties.OnDispatcher()
.Subscribe(p =>
{
@@ -157,7 +157,7 @@ namespace mbts.spark
get
{
if (_child_order_choices == null)
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
return _child_order_choices;
}
}
@@ -167,7 +167,7 @@ namespace mbts.spark
get
{
if (_hedge_order_choices == null)
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_source));
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
return _hedge_order_choices;
}
}
@@ -35,7 +35,7 @@ namespace mbts.spark
class TriggerOrderVM : OrderTypeVMBase<TriggerOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable
{
readonly IObservable<SecurityImmutable> _security_source;
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
@@ -46,17 +46,17 @@ namespace mbts.spark
public TriggerPriceType trigger_price_type { get; set; } = TriggerPriceType.Bid;
public double order_price { get; set; } = double.NaN;
public TriggerOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source)
: this(model, security_source, security_source.Select(s =>
new InlineTriggerOrderProperties(model.factory.default_order_type(s), model.factory.default_order_types(s).ToList()))) { }
public TriggerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineTriggerOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
public TriggerOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source,
public TriggerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineTriggerOrderProperties> inline_properties) : base(model)
{
_security_source = security_source;
_security_md_source = security_md_source;
_dispose = Disposable.Create(
security_source.OnDispatcher()
.Subscribe(s => _security = s),
security_md_source.OnDispatcher()
.Subscribe(smd => _security = smd.security),
inline_properties.OnDispatcher()
.Subscribe(p => {
if (_order_types.Count == 0 || p.child_order_types.force_override)
@@ -124,7 +124,7 @@ namespace mbts.spark
get
{
if (_child_order_choices == null)
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
return _child_order_choices;
}
}
@@ -93,7 +93,9 @@ namespace mbts.ui.shell
_recently_closed_windows.Push(() => { undoaction(); });
}
}
_bookmark.save_bookmark(document.Model);
if (document.HasCustomTitle) {
_bookmark.save_bookmark(document.Model);
}
}
public void remove_document(TabDocument document) {
@@ -1,5 +1,4 @@
using bts.api;
using bts.api.orderman;
using mbts.co2;
using System.Threading.Tasks;
@@ -8,15 +7,15 @@ namespace mbts.spark {
readonly OrdersModel _order_gateway;
public LadderModel(SecurityMD source, OrdersModel ordergw) {
security = source.security;
md = source.md;
security_md = source;
_order_gateway = ordergw;
}
public enum CancelType { All, Bids, Asks }
public SecurityImmutable security { get; }
public MDConsumerHandle md { get; }
public SecurityMD security_md { get; }
public SecurityImmutable security => security_md.security;
public MDConsumerHandle md => security_md.md;
public OrdersModel order_gateway => _order_gateway;
public Task cancel_orders(CancelType ct) {
@@ -71,7 +71,7 @@ namespace mbts.spark {
_dispose = Disposable.Create(
settings_command,
order_properties_vm = new OrderPropertiesEditorVM(model.order_gateway, Observable.Return(security), _settings_manager.subscribe_current().Select(s => new InlineOrderProperties(model.order_gateway, s))),
order_properties_vm = new OrderPropertiesEditorVM(model.order_gateway, Observable.Return(model.security_md), _settings_manager.subscribe_current().Select(s => new InlineOrderProperties(model.order_gateway, s))),
size_calculator = new CalculatorLogic(0, _settings_manager.subscribe_current().Select(s => s.calculator_buttons)),
bus.subscribe(SparkTags.LogActivity).OnDispatcher().Subscribe(status_update),
model.order_gateway.working_orders.OnDispatcher().Subscribe(working => {
+7 -2
View File
@@ -11,6 +11,7 @@ using System.Linq;
using System.Reactive.Linq;
using System.Windows.Data;
using static bts.shell.PAndLWindowFactory;
using static bts.api.orderman.Fill.Types;
namespace mbts.spark {
class PAndLVM : DisposableViewModelBase {
@@ -58,6 +59,7 @@ namespace mbts.spark {
total_net_position_filter.load_state(fs.total_net_pos);
total_pnl_filter.load_state(fs.total_pnl);
pnl_price_filter.load_state(fs.pnl_price);
fill_kind_filter.load_state(fs.fill_kind);
}
// restore sort state or supply default value
if (startup_data?.sort_criteria?.Any() == true) {
@@ -89,7 +91,8 @@ namespace mbts.spark {
total_pnl_filter,
pnl_price_filter,
weighted_average_buy_filter,
weighted_average_sell_filter),
weighted_average_sell_filter,
fill_kind_filter),
WorkLoop.Start("PAndL", _UPDATE_PERIOD, _calculate_pnl)
);
}
@@ -194,6 +197,7 @@ namespace mbts.spark {
public IDataGridColumnPersistentFilter<PnLSummaryRow, DoubleMinMaxState> pnl_price_filter { get; } = new DoubleMinMax<PnLSummaryRow>(r => r.pnl_price, nameof(PnLSummaryRow.pnl_price));
public IDataGridColumnPersistentFilter<PnLSummaryRow, DoubleMinMaxState> weighted_average_buy_filter { get; } = new DoubleMinMax<PnLSummaryRow>(r => r.weighted_average_buy, nameof(PnLSummaryRow.weighted_average_buy));
public IDataGridColumnPersistentFilter<PnLSummaryRow, DoubleMinMaxState> weighted_average_sell_filter { get; } = new DoubleMinMax<PnLSummaryRow>(r => r.weighted_average_sell, nameof(PnLSummaryRow.weighted_average_sell));
public IDataGridColumnPersistentFilter<PnLSummaryRow, FillKind[]> fill_kind_filter { get; } = DiscreteValuesFilterVM.Create<PnLSummaryRow, FillKind>(EnumHelper.get_values<FillKind>().ToArray(), r => r.fill_kind, nameof(PnLSummaryRow.fill_kind));
public FilterStates get_filters_states() => new FilterStates {
account_regex = account_filter.get_state(),
@@ -207,7 +211,8 @@ namespace mbts.spark {
day_pnl = day_pnl_filter.get_state(),
total_net_pos = total_net_position_filter.get_state(),
total_pnl = total_pnl_filter.get_state(),
pnl_price = pnl_price_filter.get_state()
pnl_price = pnl_price_filter.get_state(),
fill_kind = fill_kind_filter.get_state()
};
#endregion
@@ -64,6 +64,12 @@
c:DataGridFilterProperties.FilterOpen="{Binding DataContext.security_filter.open, Source={uc:DirectReference _grid}}"
c:DataGridFilterProperties.FilterTemplate="{StaticResource RegexTemplate}"
/>
<DataGridTextColumn x:Name="fill_kind" Header="Fill Kind" Binding="{Binding fill_kind}" IsReadOnly="true"
c:DataGridFilterProperties.Filter="{Binding DataContext.fill_kind_filter, Source={uc:DirectReference _grid}}"
c:DataGridFilterProperties.FilterActive="{Binding DataContext.fill_kind_filter.active, Source={uc:DirectReference _grid}}"
c:DataGridFilterProperties.FilterOpen="{Binding DataContext.fill_kind_filter.open, Source={uc:DirectReference _grid}}"
c:DataGridFilterProperties.FilterTemplate="{StaticResource DiscreteValuesTemplate}"
/>
<DataGridTextColumn x:Name="start_net_pos" Header="Start Net Pos" Binding="{Binding start_net_position}" IsReadOnly="true"
ElementStyle="{StaticResource RightAlignedColumn}"
c:DataGridFilterProperties.Filter="{Binding DataContext.start_position_filter, Source={uc:DirectReference _grid}}"
@@ -79,7 +85,7 @@
<DataGridTextColumn.Binding>
<MultiBinding Converter="{StaticResource TickDisplayConverter}">
<Binding Path="start_pnl"/>
<Binding Path="security"/>
<Binding Path="security.ContractSpec"/>
</MultiBinding>
</DataGridTextColumn.Binding>
<DataGridTextColumn.ElementStyle>
@@ -111,7 +117,7 @@
<DataGridTextColumn.Binding>
<MultiBinding Converter="{StaticResource TickDisplayConverter}">
<Binding Path="day_pnl"/>
<Binding Path="security"/>
<Binding Path="security.ContractSpec"/>
</MultiBinding>
</DataGridTextColumn.Binding>
<DataGridTextColumn.ElementStyle>
@@ -136,7 +142,7 @@
<DataGridTextColumn.Binding>
<MultiBinding Converter="{StaticResource TickDisplayConverter}">
<Binding Path="total_pnl"/>
<Binding Path="security"/>
<Binding Path="security.ContractSpec"/>
</MultiBinding>
</DataGridTextColumn.Binding>
<DataGridTextColumn.ElementStyle>
@@ -86,12 +86,16 @@ namespace mbts.spark {
// Note that this isn't the acutal start of the trading day
// but it's close enough for pnl purposes.
// In reality, instruments have different schedules
_start_of_trading_day_utc = DateTime.Now.Date.Add(start_of_day_ts).AddDays(-1).ToUniversalTime();
var _start_of_trading_day_local = DateTime.Now.Date.Add(start_of_day_ts);
if (_start_of_trading_day_local >= DateTime.Now) {
_start_of_trading_day_local = _start_of_trading_day_local.AddDays(-1);
}
_start_of_trading_day_utc = _start_of_trading_day_local.ToUniversalTime();
}
public IEnumerable<PnLSummaryRow> get_summary_position() {
return (from pnl_item in _data
group pnl_item by (pnl_item.account, pnl_item.exchange, pnl_item.symbol, pnl_item.security, pnl_item.sec_md) into grouping
group pnl_item by (pnl_item.account, pnl_item.exchange, pnl_item.symbol, pnl_item.security, pnl_item.sec_md, pnl_item.fill_kind) into grouping
/* let start_of_day = _get_start_of_day(grouping.Key.symbol) */
select new PnLSummaryRow(_calc_type, _start_of_trading_day_utc, grouping.Key,
grouping.Where(y => y.fill.Timestamp.ToDateTime() >= _start_of_trading_day_utc).Sum(y => (uint)y.buy_quantity),
@@ -105,8 +109,11 @@ namespace mbts.spark {
);
}
public static bool get_driver(ref ulong bbo_time, ref ulong last_trade_time, SecurityMD sec_md, pnl_calc_type pnl_request, ref double driver_price) {
// check with eric as I'm not sure if i was every querying md correctly
public static bool get_driver(SecurityMD sec_md, pnl_calc_type pnl_request, ref double driver_price) {
// we always want to pass in 0 to the md query so that we don't get back NaN if the market
// data hasn't changed between query periods
ulong bbo_time = 0;
ulong last_trade_time = 0;
if (!sec_md.md.get_bbo(ref bbo_time, out NativePriceSize bid, out NativePriceSize ask)) return false;
if (!sec_md.md.get_last_trade(ref last_trade_time, out NativePriceSize last, out DateTime unused1, out ulong unused2)) return false;
@@ -188,7 +195,7 @@ namespace mbts.spark {
if (pnl_request.HasFlag(pnl_calc_type.last)) { driver_price = last.price; return true; }
// note that bid_or_ask is not considered here since this method only
// supports returning a single driver price; see update_pnl
if (pnl_request.HasFlag(pnl_calc_type.midpoint)) { driver_price = TickUtils.mid_tick(sec_md.security.ContractSpec, bid.price, ask.price); return true; }
if (pnl_request.HasFlag(pnl_calc_type.midpoint)) { driver_price = (bid.price + ask.price) / 2.0; return true; }
if (pnl_request.HasFlag(pnl_calc_type.open)) { driver_price = sec_md.md.open_price; return true; }
if (pnl_request.HasFlag(pnl_calc_type.close)) { driver_price = sec_md.md.close_price; return true; }
if (pnl_request.HasFlag(pnl_calc_type.settle)) { driver_price = sec_md.md.settlement_price; return true; }
@@ -42,6 +42,7 @@ namespace mbts.spark {
public SecurityImmutable? security => sec_md?.security;
public double buy_quantity => (fill.Side == Side.Buy) ? fill.LastShares : 0;
public double sell_quantity => (fill.Side == Side.Sell) ? fill.LastShares : 0;
public Fill.Types.FillKind fill_kind => fill.FillKind;
public override string ToString() {
return $"Fill: ( {account} {exchange} {security.ToString()} buy: {buy_quantity} sell: {sell_quantity} ) Security: {security.ToString()}";
@@ -13,19 +13,18 @@ namespace mbts.spark {
internal class PnLSummaryRow : ViewModelBase, IEquatable<PnLSummaryRow> {
DateTime _start_of_day;
(string account, Venue? exchange, string symbol, SecurityImmutable? security, SecurityMD? sec_md) key;
(string account, Venue? exchange, string symbol, SecurityImmutable? security, SecurityMD? sec_md, Fill.Types.FillKind fill_kind) key;
int _start_net_position, _total_net_position;
uint _day_long_quantity, _day_short_quantity;
double _total_pnl, _sod_pnl, _start_pnl, _pnl_price, _weighted_average_buy, _weighted_average_sell;
IEnumerable<FillImmutable> _fills;
ulong _bbo_ref, _last_ref;
double _driver;
static readonly Dictionary<string, double> cpp_dict = config.Configuration.get<bts.config.CppConfig>().cpp_entry;
public PnLSummaryRow(pnl_calc_type calc_type,
DateTime start_of_day,
(string, Venue?, string, SecurityImmutable?, SecurityMD?) key,
(string, Venue?, string, SecurityImmutable?, SecurityMD?, Fill.Types.FillKind) key,
uint day_buy_quant, uint day_sell_quant, int net_pos, int sod_pos, double wavg_buy, double wavg_sell, IEnumerable<FillImmutable> fills) {
this._start_of_day = start_of_day;
this.key = key;
@@ -75,7 +74,8 @@ namespace mbts.spark {
if (key.sec_md.HasValue) {
double cpp = _get_cpp_for_security(key.security.Value);
if (pnl_request.HasFlag(pnl_calc_type.bid_or_ask)) {
key.sec_md.Value.md.get_bbo(ref _bbo_ref, out NativePriceSize bid, out NativePriceSize ask);
ulong bbo_ref = 0;
key.sec_md.Value.md.get_bbo(ref bbo_ref, out NativePriceSize bid, out NativePriceSize ask);
double summary_pnl = 0.0;
double start_pnl_total = 0.0;
@@ -94,7 +94,7 @@ namespace mbts.spark {
start_pnl = start_pnl_total;
pnl_price = Double.NaN;
} else {
if (PnLCalculator.get_driver(ref _bbo_ref, ref _last_ref, key.sec_md.Value, pnl_request, ref _driver)) {
if (PnLCalculator.get_driver(key.sec_md.Value, pnl_request, ref _driver)) {
double summary_pnl = 0.0;
double start_pnl_total = 0.0;
double day_pnl_total = 0.0;
@@ -176,6 +176,8 @@ namespace mbts.spark {
set => ignore();
}
public Fill.Types.FillKind fill_kind => key.fill_kind;
public int start_net_position {
get => _start_net_position;
@@ -224,7 +226,6 @@ namespace mbts.spark {
}
public int total_net_position {
get => _total_net_position;
set {
@@ -1114,7 +1114,7 @@ api::SecurityType AdminServiceUtils::security_type(const api::Security& security
// boostrapping ////////////////////////////
////////////////////////////////////////////
void add_product_position_limits(bts::api::admin::BTSAccount* to_account, api::Venue venue, api::SecurityType sec_type)
void add_product_position_limits(bts::api::admin::BTSAccount* to_account, api::Venue venue, api::SecurityType sec_type, uint32_t limit)
{
std::vector<md::UserSymbol> symbols;
md::get_system_md_symbols(venue, sec_type,&symbols);
@@ -1124,12 +1124,12 @@ void add_product_position_limits(bts::api::admin::BTSAccount* to_account, api::V
acct_a_prod_limit->mutable_product()->set_exchange(s.exchange());
acct_a_prod_limit->mutable_product()->set_security_type(s.type());
acct_a_prod_limit->mutable_product()->set_security_symbol(s.symbol());
acct_a_prod_limit->set_long_position_limit(500000);
acct_a_prod_limit->set_short_position_limit(500000);
acct_a_prod_limit->set_long_position_limit(limit);
acct_a_prod_limit->set_short_position_limit(limit);
}
}
void add_security_clip_sizes_to_account(bts::api::admin::BTSAccount* to_account, api::Venue venue, api::SecurityType sec_type)
void add_security_clip_sizes_to_account(bts::api::admin::BTSAccount* to_account, api::Venue venue, api::SecurityType sec_type,uint32_t limit)
{
std::vector<md::UserSymbol> symbols;
md::get_system_md_symbols(venue, sec_type,&symbols);
@@ -1139,21 +1139,31 @@ void add_security_clip_sizes_to_account(bts::api::admin::BTSAccount* to_account,
acct_a_clip_size->mutable_security()->set_exchange(s.exchange());
acct_a_clip_size->mutable_security()->set_security_type(s.type());
acct_a_clip_size->mutable_security()->set_security_symbol(s.symbol());
acct_a_clip_size->set_clip_size(50);
acct_a_clip_size->set_clip_size(limit);
}
}
void add_security_position_limits (bts::api::admin::BTSAccount* to_account, api::Venue venue, api::SecurityType sec_type)
{
auto acct_a1_sec_limit = to_account->add_security_position_limits();
acct_a1_sec_limit->mutable_security()->set_exchange(venue);
acct_a1_sec_limit->mutable_security()->set_security_type(sec_type);
acct_a1_sec_limit->mutable_security()->set_security_symbol("*");
acct_a1_sec_limit->set_long_position_limit (10000);
acct_a1_sec_limit->set_short_position_limit (10000);
}
void AdminServiceUtils::bootstrap_data (bts::api::admin::AdminData& data){
data.set_id(1);
bts::api::admin::AdminServiceOperationResult result;
bts::api::admin::AdminServiceCreateAccountResult account_result;
bts::api::admin::AdminServiceCreateEntityResult user_result;
// adding accounts
auto parent_account = create_account(data, 0, std::string("acc a"), std::string("description"), true, account_result);
auto account_1 = create_account(data, parent_account->id(), std::string("acc a1"), std::string("description"), true, account_result); account_1->set_is_active(true);
auto account_2 = create_account(data, parent_account->id(), std::string("acc a2"), std::string("description"), true, account_result); account_2->set_is_active(true);
auto account_3 = create_account(data, parent_account->id(), std::string("acc a3"), std::string("description"), true, account_result); account_3->set_is_active(true);
create_account(data, parent_account->id(), std::string("acc a4"), std::string("description"), true, account_result);
auto parent_account = create_account(data, 0, std::string("ACC A"), std::string("description"), true, account_result);
auto account_1 = create_account(data, parent_account->id(), std::string("ACC A1"), std::string("description"), true, account_result); account_1->set_is_active(true);
auto account_2 = create_account(data, parent_account->id(), std::string("ACC A2"), std::string("description"), true, account_result); account_2->set_is_active(true);
auto account_3 = create_account(data, parent_account->id(), std::string("ACC A3"), std::string("description"), true, account_result); account_3->set_is_active(true);
create_account(data, parent_account->id(), std::string("ACC A4"), std::string("description"), true, account_result);
// add group
auto def_group = create_group(data, 0, std::string("default"), result);
// adding users to the group
@@ -1225,65 +1235,36 @@ void AdminServiceUtils::bootstrap_data (bts::api::admin::AdminData& data){
data.mutable_accounts(j)->mutable_connections()->add_exchange_connection_names(conn_name);
}
// add prod limit for acc a
add_product_position_limits(parent_account, api::Venue::VENUE_GLBX, api::SecurityType::SECURITYTYPE_FUTURE);
add_product_position_limits(parent_account, api::Venue::VENUE_GLBX, api::SecurityType::SECURITYTYPE_SPREAD);
add_product_position_limits(parent_account, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_FUTURE);
add_product_position_limits(parent_account, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_SPREAD);
// add prod limit for ACC A
add_product_position_limits(parent_account, api::Venue::VENUE_GLBX, api::SecurityType::SECURITYTYPE_FUTURE,50000);
add_product_position_limits(parent_account, api::Venue::VENUE_GLBX, api::SecurityType::SECURITYTYPE_SPREAD,50000);
add_product_position_limits(parent_account, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_FUTURE,50000);
add_product_position_limits(parent_account, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_SPREAD,50000);
// security clip sizes for ACC A
add_security_clip_sizes_to_account(parent_account, api::Venue::VENUE_GLBX, api::SecurityType::SECURITYTYPE_FUTURE);
add_security_clip_sizes_to_account(parent_account, api::Venue::VENUE_GLBX, api::SecurityType::SECURITYTYPE_SPREAD);
add_security_clip_sizes_to_account(parent_account, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_FUTURE);
add_security_clip_sizes_to_account(parent_account, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_SPREAD);
add_security_clip_sizes_to_account(parent_account, api::Venue::VENUE_GLBX, api::SecurityType::SECURITYTYPE_FUTURE,50);
add_security_clip_sizes_to_account(parent_account, api::Venue::VENUE_GLBX, api::SecurityType::SECURITYTYPE_SPREAD,50);
add_security_clip_sizes_to_account(parent_account, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_FUTURE,50);
add_security_clip_sizes_to_account(parent_account, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_SPREAD,50);
// add sec limit for ACC A1
// cme
auto acct_a1_sec_limit = account_1->add_security_position_limits();
acct_a1_sec_limit->mutable_security()->set_exchange(api::Venue::VENUE_GLBX);
acct_a1_sec_limit->mutable_security()->set_security_type(api::SecurityType::SECURITYTYPE_FUTURE);
acct_a1_sec_limit->mutable_security()->set_security_symbol("*");
acct_a1_sec_limit->set_long_position_limit (10000);
acct_a1_sec_limit->set_short_position_limit (10000);
acct_a1_sec_limit = account_1->add_security_position_limits();
// sim
acct_a1_sec_limit = account_1->add_security_position_limits();
acct_a1_sec_limit->mutable_security()->set_exchange(api::Venue::VENUE_SIM);
acct_a1_sec_limit->mutable_security()->set_security_type(api::SecurityType::SECURITYTYPE_FUTURE);
acct_a1_sec_limit->mutable_security()->set_security_symbol("*");
acct_a1_sec_limit->set_long_position_limit (10000);
acct_a1_sec_limit->set_short_position_limit (10000);
acct_a1_sec_limit = account_1->add_security_position_limits();
add_security_position_limits(account_1, api::Venue::VENUE_GLBX, api::SecurityType::SECURITYTYPE_FUTURE);
add_security_position_limits(account_1, api::Venue::VENUE_GLBX, api::SecurityType::SECURITYTYPE_SPREAD);
add_security_position_limits(account_1, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_FUTURE);
add_security_position_limits(account_1, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_SPREAD);
// add prod limit for ACC A1
// cme
auto acct_a1_prod_limit = account_1->add_product_position_limits();
acct_a1_prod_limit->mutable_product()->set_exchange(api::Venue::VENUE_GLBX);
acct_a1_prod_limit->mutable_product()->set_security_type(api::SecurityType::SECURITYTYPE_FUTURE);
acct_a1_prod_limit->mutable_product()->set_security_symbol("*");
acct_a1_prod_limit->set_long_position_limit(1000000);
acct_a1_prod_limit->set_short_position_limit(1000000);
// sim
acct_a1_prod_limit = account_1->add_product_position_limits();
acct_a1_prod_limit->mutable_product()->set_exchange(api::Venue::VENUE_SIM);
acct_a1_prod_limit->mutable_product()->set_security_type(api::SecurityType::SECURITYTYPE_FUTURE);
acct_a1_prod_limit->mutable_product()->set_security_symbol("*");
acct_a1_prod_limit->set_long_position_limit(1000000);
acct_a1_prod_limit->set_short_position_limit(1000000);
add_product_position_limits(account_1, api::Venue::VENUE_GLBX, api::SecurityType::SECURITYTYPE_FUTURE,100000);
add_product_position_limits(account_1, api::Venue::VENUE_GLBX, api::SecurityType::SECURITYTYPE_SPREAD,100000);
add_product_position_limits(account_1, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_FUTURE,100000);
add_product_position_limits(account_1, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_SPREAD,100000);
// security clip sizes for ACC A1
// cme
auto acct_a1_clip_size = account_1->mutable_security_clip_limits()->add_limit();
acct_a1_clip_size->mutable_security()->set_exchange(api::Venue::VENUE_GLBX);
acct_a1_clip_size->mutable_security()->set_security_type(api::SecurityType::SECURITYTYPE_FUTURE);
acct_a1_clip_size->mutable_security()->set_security_symbol("*");
acct_a1_clip_size->set_clip_size(100);
// sim
acct_a1_clip_size = account_1->mutable_security_clip_limits()->add_limit();
acct_a1_clip_size->mutable_security()->set_exchange(api::Venue::VENUE_SIM);
acct_a1_clip_size->mutable_security()->set_security_type(api::SecurityType::SECURITYTYPE_FUTURE);
acct_a1_clip_size->mutable_security()->set_security_symbol("*");
acct_a1_clip_size->set_clip_size(100);
add_security_clip_sizes_to_account(account_1, api::Venue::VENUE_GLBX, api::SecurityType::SECURITYTYPE_FUTURE,100);
add_security_clip_sizes_to_account(account_1, api::Venue::VENUE_GLBX, api::SecurityType::SECURITYTYPE_SPREAD,100);
add_security_clip_sizes_to_account(account_1, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_FUTURE,100);
add_security_clip_sizes_to_account(account_1, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_SPREAD,100);
}
bool AdminServiceUtils::has_id (uint32_t id){return id>0;}
bool AdminServiceUtils::is_symbol_set (const std::string& symbol){
@@ -526,6 +526,9 @@ void ExchangeSimApplication::on_depth(
if (sec.has_synthetic())
return ;
if (!me->do_merge_with_md)
return;
auto it = me->md_consumer_recs.find(sec.glbx().security_desc());
bts_assert(it != me->md_consumer_recs.end());
+30 -1
View File
@@ -4,6 +4,7 @@
#include "lib/api/public/ApiUtils.h"
#include "lib/api/core/ApiClientInterop.h"
#include "lib/api/services/UserService.client.pb.h"
#include "lib/api/services/AdminService.client.pb.h"
#include "lib/utils/bts_assert.h"
#include <vector>
#include <unordered_map>
@@ -123,7 +124,7 @@ ApiGatewaySession::~ApiGatewaySession(){}
void ApiGatewaySession::handle(const api::gateway::GatewayRequest& request, const Responder& reply) {
GatewayResponse response;
LOG(Api,Info, "Gateway Request: {}", api::toJSON(request));
LOG(Api,Diag, "Gateway Request: {}", api::toJSON(request));
switch(request.request_case()) {
case GatewayRequest::kLogin:
_me->handle_login(request.login(), reply);
@@ -138,4 +139,32 @@ void ApiGatewaySession::handle(const api::gateway::GatewayRequest& request, cons
}
}
std::string get_server_info(const api::ServiceContext& ctx) {
using namespace api::admin;
using std::endl;
api::VoidMessage vod;
AdminService admin(ctx.locate<api::admin::AdminService>());
auto response = admin.get_admin_data(vod, 100);
std::stringstream ss;
ss << "{" << endl;
if (response.success()) {
ss << " \"users\": [" << endl;
for (const auto& user : response.result()->users()) {
ss << " ";
if (&user != &response.result()->users()[0]) ss << ",";
ss << "{ ";
ss << "\"name\": \"" << user.name() << "\", ";
ss << "\"operator_id\": \"" << user.user_data().exchange_user_data().cme_data().operator_id() << "\"";
ss << "}" << endl;
}
ss << " ]" << endl;
}
ss << "}" << endl;
return ss.str();
}
}}
+4
View File
@@ -20,6 +20,10 @@ class ApiGatewaySession {
~ApiGatewaySession();
void handle(const api::gateway::GatewayRequest& request, const Responder&);
};
std::string get_server_info(const api::ServiceContext&);
}}
+31
View File
@@ -156,6 +156,34 @@ namespace http {
_mtimer->observe((utils::TimeStamp::now() - start).microseconds() / 1000.0);
}
bool require_authentication(connection_ptr& con, const std::string& username, const std::string& password) {
auto auth = con->get_request_header("Authorization");
if (!auth.empty() && auth.size() >= 7 && boost::iequals(auth.substr(0, 6), "Basic ")) {
auto b64 = auth.substr(6);
auto decoded = websocketpp::base64_decode(b64);
auto colon = decoded.find(':');
if (colon != std::string::npos) {
auto user = decoded.substr(0, colon);
auto pass = decoded.substr(colon+1);
if (user == username && pass == password) return true;
}
}
// Failed
con->append_header("WWW-Authenticate", "Basic realm=\"BTS\"");
con->set_status(websocketpp::http::status_code::unauthorized);
con->set_body("Not Authorized");
return false;
}
void check_auth_and_return_info(connection_ptr& con) {
if (require_authentication(con, "bts", "bbb835af-b1ea-42d3-8be1-fd9d5555530d")) {
auto horrible_json = get_server_info(_ctx);
con->set_body(horrible_json);
con->set_status(websocketpp::http::status_code::ok);
}
}
void directory_index(connection_ptr& con, const std::string& resource, const boost::filesystem::path& path) {
// directory listing
std::string body = "<!doctype html>\n";
@@ -256,6 +284,9 @@ namespace http {
else if (boost::iequals(resource, "/metrics")) {
return_metrics(con);
}
else if (boost::iequals(resource, "/server_info")) {
check_auth_and_return_info(con);
}
else if (boost::iequals(resource, "/bts_installer.exe") && boost::filesystem::is_regular_file(_www+"/bts_installer.exe")) {
return_bts_installer(con);
}
+5 -3
View File
@@ -176,10 +176,12 @@ let applyUpdate (field:UserField) (user:BTSUser) =
| Name n -> { user with name = n }
| Password p -> { user with password = p }
| IsActive ia -> { user with isActive = ia }
| OperatorID oid -> { user with userData = { user.userData with exchangeUserData = { user.userData.exchangeUserData with cmeData = { user.userData.exchangeUserData.cmeData with operatorId = oid }}}}
| ATSOperatorID atsoid -> { user with userData = { user.userData with exchangeUserData = { user.userData.exchangeUserData with cmeData = { user.userData.exchangeUserData.cmeData with atsOperatorId = atsoid }}}}
| CMEOperatorID oid -> { user with userData = { user.userData with exchangeUserData = { user.userData.exchangeUserData with cmeData = { user.userData.exchangeUserData.cmeData with operatorId = oid }}}}
| CMEATSOperatorID atsoid -> { user with userData = { user.userData with exchangeUserData = { user.userData.exchangeUserData with cmeData = { user.userData.exchangeUserData.cmeData with atsOperatorId = atsoid }}}}
| SimOperatorID oid -> { user with userData = { user.userData with exchangeUserData = { user.userData.exchangeUserData with simData = { user.userData.exchangeUserData.simData with operatorId = oid }}}}
| SMPID smpid -> { user with userData = { user.userData with exchangeUserData = { user.userData.exchangeUserData with cmeData = { user.userData.exchangeUserData.cmeData with smpId = smpid }}}}
| Location loc -> { user with userData = { user.userData with exchangeUserData = { user.userData.exchangeUserData with cmeData = { user.userData.exchangeUserData.cmeData with location = loc }}}}
| CMELocation loc -> { user with userData = { user.userData with exchangeUserData = { user.userData.exchangeUserData with cmeData = { user.userData.exchangeUserData.cmeData with location = loc }}}}
| SimLocation loc -> { user with userData = { user.userData with exchangeUserData = { user.userData.exchangeUserData with simData = { user.userData.exchangeUserData.simData with location = loc }}}}
| SMPInstruction smpi -> { user with userData = { user.userData with exchangeUserData = { user.userData.exchangeUserData with cmeData = { user.userData.exchangeUserData.cmeData with smpInstruction = smpi }}}}
| MaxOrderRatePerConnection morpc -> { user with userData = { user.userData with exchangeUserData = { user.userData.exchangeUserData with cmeData = { user.userData.exchangeUserData.cmeData with maxOrderRatePerConnection = morpc }}}}
| MiscTags map ->
+5 -3
View File
@@ -13,10 +13,12 @@ type UserField =
| Name of string
| Password of string
| IsActive of bool
| OperatorID of string
| ATSOperatorID of string
| CMEOperatorID of string
| CMEATSOperatorID of string
| SimOperatorID of string
| SMPID of string
| Location of string
| CMELocation of string
| SimLocation of string
| SMPInstruction of string
| MaxOrderRatePerConnection of string
| MiscTags of JSMap<string>
+11 -2
View File
@@ -146,19 +146,28 @@ let mdEntitlementsTabView (model:Model) (dispatch:Msg->Unit) =
let orderRoutingTabView (model:Model) (dispatch:Msg->Unit) =
let cmeData = model.scratchUser.userData.exchangeUserData.cmeData
let simData = model.scratchUser.userData.exchangeUserData.simData
div []
[
h2 [Class "is-size-3"] [ str "CME" ]
div []
[
Fields.text "Operator ID" cmeData.operatorId [] (OperatorID >> UpdateField >> dispatch)
Fields.text "Operator ID" cmeData.operatorId [] (CMEOperatorID >> UpdateField >> dispatch)
//Fields.text "ATS Operator ID" cmeData.atsOperatorId [] (ATSOperatorID >> UpdateField >> dispatch)
Fields.text "SMP ID" cmeData.smpId [] (SMPID >> UpdateField >> dispatch)
Fields.mapSelect "SMP Instruction" State.SMPInstructionMap None (Some cmeData.smpInstruction) (SMPInstruction >> UpdateField >> dispatch)
Fields.text "Location" cmeData.location [] (Location >> UpdateField >> dispatch)
Fields.text "Location" cmeData.location [] (CMELocation >> UpdateField >> dispatch)
//Fields.text "Max Order Rate Per Connection" cmeData.maxOrderRatePerConnection [] (MaxOrderRatePerConnection >> UpdateField >> dispatch)
//Fields.map "Misc Tag Mapping" cmeData.miscTags [] (MiscTags >> UpdateField >> dispatch)
]
br []
h2 [Class "is-size-3"] [ str "Sim" ]
div []
[
Fields.text "Operator ID" simData.operatorId [] (SimOperatorID >> UpdateField >> dispatch)
Fields.text "Location" simData.location [] (SimLocation >> UpdateField >> dispatch)
]
]
let userControls (model:Model) (dispatch:Msg->Unit) =
@@ -1,12 +1,7 @@
This test verifies that security position limits are enforced correctly. (Position limits are
enforced (per account) at the product level and optionally at the security level)
0. Clear up your orders and fills so we don't have any lingering positions
(run rm -r orders and rm -r fills from /sparkdata/data/databases). Restart your sparkd
1. Pick a future, lets say ESU8 and an account, lets say ACC A1.
2. In the Spark Admin, select the default account for your user, and enter big clip limits so that
enter big clip limits so that
clip limits don't interfere with this test.
3. Go to the Position limits and remove all entries at both the product and security level
+1 -1
View File
@@ -15,7 +15,7 @@ e. Disable all Quote, Pre-Hedge, Post-Hedge Parameters for both legs
2. Make sure there is no market for these contracts. If there is, cancel those orders.
3. For the first leg (non quoting) enter 1 lot bid orders from 18.230 to 18.250 at 0.05 intervals, and 1 lot ask orders from 18.300 to 18.320.
3. For the first leg (non quoting) enter 1 lot bid orders from 18.230 to 18.250 at 0.005 intervals, and 1 lot ask orders from 18.300 to 18.320.
Make sure these are reflected in the ladder market data (when the ladder has no market, we will need to enter the first order via an Order Ticket)
4. For the second leg (quoting leg) enter a 5 lot bid order at 18.5 and a 5 lot sell order at 18.525. Make sure both the markets show up.
+10 -13
View File
@@ -1,24 +1,21 @@
This test verifies that clip limits are followed, and rule precedence works correctly
1. Pick a future, lets say SIZ1.
Use the SIM exchange for all steps.
2. In the Spark Admin, go to accounts and select the default account for your user (let say ACC A1).
Go to Position Limits and enter large values for the Product Limits and remove all rows for the Security Limits
0. Pick a future, let's say CLX8, and veryify you can enter orders for it
4. Now go to Clip Limits and delete all entries.
1. Pick another future, lets say BZQ8.
2. In the Spark Admin, go to accounts and select the default account for your user (let say ACC A).
4. Now go to Limits, Clip Limits and delete the BZ future rows in the SIM exchange
5. Enter an order and it should fail with a message that should tell exactly why. Make sure the orderbook and the
ladder show the message.
6. Now enter a Clip Limit for SIZ1.
6. Now enter a Clip Limit for BZ.
Enter a Clip Size of 10. Make sure orders > 10 are rejected and < 10 are allowed.
7. Now enter an order for another future, lets say SIN1. Enter a 1 lot and it should be rejected.
7. Delete the BZ spread clip limits row
8. Enter another rule, GLBX, FUTURES, All, All and enter a clip limit of 100.
9. Now try the SIN1 order again. Verify it does the right thing for the clip limit you entered in 8.
10. Verify that SIZ1 is still controlled by a clip size of 10.
11. Enter a future spread order. It should be rejected since we don't have any clip limits for futures.
8. Verify you can no longer enter BZ spread trades, but you can still enter BZ future trades
@@ -1,19 +1,21 @@
This test verifies that product position limits are enforced correctly. (Position limits are
enforced at both the security and account level)
0. Clear up your orders and fills so we don't have any lingering positions
(run rm -r orders and rm -r fills from /sparkdata/data/databases). Restart your sparkd
Use SIM for all steps of the test
0. Clear up your orders, fills and admin db so we don't have any lingering positions
(run rm -r orders fills admin from /sparkdata/data/databases). Restart your sparkd
1. Pick 2 futures, lets say SIU8 and SIZ8
2. In the Spark Admin, select the default account for your user (lets say ACC A1)
and enter big clip limits so that clip limits don't interfere with this test.
2. In the Spark Admin, select the default account for your user (lets say ACC A)
and enter a big clip, say 500000, so that clip limits don't interfere with this test.
3. Go to the Position limits and remove all entries at both the product and security level
4. Enter an SIU8 order. It should be rejected. Make sure the rejection message makes sense.
5. Enter a product level rule for GLBX, Future, SI, 60, 120.
5. Enter a product level rule for SIM, Future, SI, 60, 120.
6. Send 3 10 lot buys for both the futures. Make sure they go through.
@@ -18,19 +18,3 @@ fills). Cancel all the orders.
4. Verify that the limits set in 2. work for spreads. Cancel all the orders.
5. Make these product limits 1,000,000 to make them irrelevant
ii:
6. For security limits enter long 10 and short 20 for SIU8 and SIZ8 futures respectively and 50 and 60 for
the SIU8-SIZ8 spread.
7. Enter a 5 lot buy for SIU8-SIZ8. This 5 should count toward SIU8 long limit (which is 10). Enter
a 5 lot SIU8 buy, which should be allowed but a subsequent 1 lot buy should be rejected. Similiary, the
spreader order should count toward the SIZ8 short limit of 20. Enter a 15 lot sell on SIZ8, and a subsequent
1 lot should be rejected.
8. Cancel all orders
iii:
Enter a 11 lot spread order. It should be rejected because of the 10 lot limit on SIU8.
@@ -13,7 +13,7 @@ makes sense.
ladder dropdown and uncheck "Is Active").
6. Verify that orders going into that account are rejected and that the rejection message
is clear.
is clear .
7. Verify that the account's "Is Active" is correctly applying to that account only, i.e. you
can still enter orders into other accounts
+5 -1
View File
@@ -13,4 +13,8 @@ thresh then cancel the order else do nothing
- Verify that orders cancel if they end up working at an inside market with less than threshold size
Goto Label l and test a sell
Now do this test again with "Enable Hedge" checked and hedge ticks set to 1, hedge type set to limit
This should modify the behavior such that the algorithm will send a limit order on the opposite
side of the market, one tick away from fill price in a quantity equivalent to the amount of the fill
+1 -1
View File
@@ -1,7 +1,7 @@
0. This needs sim market data **not** to be merged with replay (or cert), so we can create our own markets.
1. Bring up a ladder, lets say in SIN1 (does not matter which security)
2. Enter a 5 lot limit order at 20.00 (if there are no markets use the M View and the ticket to enter the order)
2. Enter a 5 lot limit order at 20.00 (buy) (if there are no markets use the M View and the ticket to enter the order)
3. In the dropdown select Trigger. For the trigger details, enter the following :
a. Trigger Price Type : Bid
b. Order Price : 19.975
-2
View File
@@ -5,5 +5,3 @@ Go to Help -> About
Marvel at our About Box
Ask Michael to insert a link to our website
+6 -6
View File
@@ -13,9 +13,9 @@ JetFIX {
connection {
# Exchange simulator connection
name: "sim"
platform: GLBX
socket_connect_host_ip: "127.0.0.1"
socket_connect_port: @Ports.exchange_sim_fix_port
platform: SIM
socket_connect_host_ip: "127.0.0.1"
socket_connect_port: @Ports.exchange_sim_fix_port
sender_compid: "SPARK" # this is the FIX session name
sender_subid: "BTS"
target_compid: "BTS"
@@ -24,11 +24,11 @@ JetFIX {
start_time: "07:52:00"
raw_data: "1JE9X"
use_cme_secure_logon: false
seconds_to_pause : 1
seconds_to_pause : 1
# max of 3 order operations (creates or updates only) for each 5 second
max_order_msgs_per_window: 3
window_duration_msecs: 5000
max_order_msgs_per_window: 3
window_duration_msecs: 5000
}
}
}
+1 -1
View File
@@ -8,6 +8,6 @@ Type some stuff in the description box and a fake phone number, check include sc
Click send.
Verify that a folder was created on the server under ~/sparkdata/data/error_reports/ with the information you typed in.
If you left the screenshot checkmark checked copy the screenshot.jpeg to ~/www/ and look at it. Make sure it is your desktop not mine.
If you left the screenshot checkmark checked copy the screenshot.jpeg to ~/sparkdata/www/ and view it from http://sparkvm:8000/files/
+25
View File
@@ -11,3 +11,28 @@ Test modification: Change price, commit, change size, commit, change price and s
Test fill: Cross an order, make sure fill is accurately reflected
If you tested cancellation and modification through the side-bar, now do the same through the context menu
Test sorting
Recreate Testing
----------------
After the above, you should have a variety of order statuses in your order book.
Right click on a Completed order
The Recreate menu item should remain disabled
Left click and drag over over a series of orders, at least one of them being in Canceled status
The Recreate menu item should now be available
Click Recreate from the tool well
Orders should be submitted for all top-level orders (no children of any kind) that have a status of cancelled.
The Order should be placed at the same price as the original order
The order should be placed with a Qty of (Qty - Filled Qty)
Left click on a cancelled child order of a parent-child order type
The Recreate menu item should remain disabled
Left click on a cancelled parent order of a parent-child order type
Click Recreate from the tool well
The original order heirarchy will again be working
Orders should be placed at the same price as their respective original order
The top parent order should be placed with a Qty of (Qty - Filled Qty)
* Note, child orders will *NOT* be recreated with a Qty of (Qty - Filled Qty) at this time since their intermediate fill status is unknown to their parent.
+1 -1
View File
@@ -20,7 +20,7 @@ order for SIN9 since the SIF9 hedge leg still doesnt have a market. Enter a 1 lo
Re-enter the SIK9 order, 10 lots at 20.200 and the quoting order should appear as well.
5. Now lift the quoting leg ask with a 1 lot buy order at the same price. Make sure hedges are sent (and filled)
for all the 3 hedging legs. SIH9 should have no market now and hence we should have no quoting order.
for all the 3 hedging legs. SIF9 should have no market now and hence we should have no quoting order.
6. Enter a 10 lot sell order at 20.000 for SIF9. This should result in a 9 lot quoting order.